couchbase 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -4
  3. data/ext/build_config.hxx.in +2 -0
  4. data/ext/build_version.hxx.in +11 -8
  5. data/ext/cmake/BuildTracing.cmake +1 -1
  6. data/ext/cmake/CompilerWarnings.cmake +5 -0
  7. data/ext/cmake/Testing.cmake +3 -6
  8. data/ext/couchbase/bucket.hxx +9 -1
  9. data/ext/couchbase/cbsasl/client.h +1 -1
  10. data/ext/couchbase/cluster.hxx +89 -6
  11. data/ext/couchbase/configuration.hxx +2 -0
  12. data/ext/couchbase/couchbase.cxx +1647 -507
  13. data/ext/couchbase/diagnostics.hxx +0 -3
  14. data/ext/couchbase/io/dns_client.hxx +2 -2
  15. data/ext/couchbase/io/http_command.hxx +6 -3
  16. data/ext/couchbase/io/http_session.hxx +14 -18
  17. data/ext/couchbase/io/http_session_manager.hxx +83 -2
  18. data/ext/couchbase/io/mcbp_command.hxx +4 -1
  19. data/ext/couchbase/io/mcbp_context.hxx +37 -0
  20. data/ext/couchbase/io/mcbp_session.hxx +91 -30
  21. data/ext/couchbase/operations.hxx +5 -0
  22. data/ext/couchbase/operations/analytics_dataset_create.hxx +3 -2
  23. data/ext/couchbase/operations/analytics_dataset_drop.hxx +3 -2
  24. data/ext/couchbase/operations/analytics_dataset_get_all.hxx +3 -2
  25. data/ext/couchbase/operations/analytics_dataverse_create.hxx +3 -2
  26. data/ext/couchbase/operations/analytics_dataverse_drop.hxx +3 -2
  27. data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +3 -2
  28. data/ext/couchbase/operations/analytics_index_create.hxx +3 -2
  29. data/ext/couchbase/operations/analytics_index_drop.hxx +3 -2
  30. data/ext/couchbase/operations/analytics_index_get_all.hxx +5 -2
  31. data/ext/couchbase/operations/analytics_link_connect.hxx +3 -2
  32. data/ext/couchbase/operations/analytics_link_disconnect.hxx +3 -2
  33. data/ext/couchbase/operations/bucket_create.hxx +3 -2
  34. data/ext/couchbase/operations/bucket_drop.hxx +3 -2
  35. data/ext/couchbase/operations/bucket_flush.hxx +3 -2
  36. data/ext/couchbase/operations/bucket_get.hxx +3 -2
  37. data/ext/couchbase/operations/bucket_get_all.hxx +3 -2
  38. data/ext/couchbase/operations/bucket_update.hxx +3 -2
  39. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +3 -2
  40. data/ext/couchbase/operations/collection_create.hxx +3 -2
  41. data/ext/couchbase/operations/collection_drop.hxx +3 -2
  42. data/ext/couchbase/operations/collections_manifest_get.hxx +3 -2
  43. data/ext/couchbase/operations/document_analytics.hxx +3 -2
  44. data/ext/couchbase/operations/document_append.hxx +77 -0
  45. data/ext/couchbase/operations/document_decrement.hxx +3 -2
  46. data/ext/couchbase/operations/document_exists.hxx +3 -2
  47. data/ext/couchbase/operations/document_get.hxx +3 -2
  48. data/ext/couchbase/operations/document_get_and_lock.hxx +3 -2
  49. data/ext/couchbase/operations/document_get_and_touch.hxx +3 -2
  50. data/ext/couchbase/operations/document_get_projected.hxx +3 -2
  51. data/ext/couchbase/operations/document_increment.hxx +3 -2
  52. data/ext/couchbase/operations/document_insert.hxx +3 -2
  53. data/ext/couchbase/operations/document_lookup_in.hxx +8 -2
  54. data/ext/couchbase/operations/document_mutate_in.hxx +13 -2
  55. data/ext/couchbase/operations/document_prepend.hxx +77 -0
  56. data/ext/couchbase/operations/document_query.hxx +3 -2
  57. data/ext/couchbase/operations/document_remove.hxx +5 -2
  58. data/ext/couchbase/operations/document_replace.hxx +3 -2
  59. data/ext/couchbase/operations/document_search.hxx +3 -2
  60. data/ext/couchbase/operations/document_touch.hxx +3 -2
  61. data/ext/couchbase/operations/document_unlock.hxx +3 -2
  62. data/ext/couchbase/operations/document_upsert.hxx +3 -2
  63. data/ext/couchbase/operations/document_view.hxx +3 -2
  64. data/ext/couchbase/operations/group_drop.hxx +3 -2
  65. data/ext/couchbase/operations/group_get.hxx +3 -2
  66. data/ext/couchbase/operations/group_get_all.hxx +3 -2
  67. data/ext/couchbase/operations/group_upsert.hxx +3 -2
  68. data/ext/couchbase/operations/http_noop.hxx +78 -0
  69. data/ext/couchbase/operations/mcbp_noop.hxx +61 -0
  70. data/ext/couchbase/operations/query_index_build_deferred.hxx +3 -2
  71. data/ext/couchbase/operations/query_index_create.hxx +3 -2
  72. data/ext/couchbase/operations/query_index_drop.hxx +3 -2
  73. data/ext/couchbase/operations/query_index_get_all.hxx +3 -2
  74. data/ext/couchbase/operations/role_get_all.hxx +3 -2
  75. data/ext/couchbase/operations/scope_create.hxx +3 -2
  76. data/ext/couchbase/operations/scope_drop.hxx +3 -2
  77. data/ext/couchbase/operations/scope_get_all.hxx +3 -2
  78. data/ext/couchbase/operations/search_get_stats.hxx +3 -2
  79. data/ext/couchbase/operations/search_index_analyze_document.hxx +3 -2
  80. data/ext/couchbase/operations/search_index_control_ingest.hxx +3 -2
  81. data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +3 -2
  82. data/ext/couchbase/operations/search_index_control_query.hxx +3 -2
  83. data/ext/couchbase/operations/search_index_drop.hxx +3 -2
  84. data/ext/couchbase/operations/search_index_get.hxx +3 -2
  85. data/ext/couchbase/operations/search_index_get_all.hxx +3 -2
  86. data/ext/couchbase/operations/search_index_get_documents_count.hxx +3 -2
  87. data/ext/couchbase/operations/search_index_get_stats.hxx +3 -2
  88. data/ext/couchbase/operations/search_index_upsert.hxx +3 -2
  89. data/ext/couchbase/operations/user_drop.hxx +3 -2
  90. data/ext/couchbase/operations/user_get.hxx +3 -2
  91. data/ext/couchbase/operations/user_get_all.hxx +3 -2
  92. data/ext/couchbase/operations/user_upsert.hxx +3 -2
  93. data/ext/couchbase/operations/view_index_drop.hxx +3 -2
  94. data/ext/couchbase/operations/view_index_get.hxx +3 -2
  95. data/ext/couchbase/operations/view_index_get_all.hxx +3 -2
  96. data/ext/couchbase/operations/view_index_upsert.hxx +3 -2
  97. data/ext/couchbase/platform/terminate_handler.cc +5 -2
  98. data/ext/couchbase/protocol/client_opcode.hxx +368 -0
  99. data/ext/couchbase/protocol/cmd_append.hxx +145 -0
  100. data/ext/couchbase/protocol/cmd_hello.hxx +1 -0
  101. data/ext/couchbase/protocol/cmd_lookup_in.hxx +11 -3
  102. data/ext/couchbase/protocol/cmd_mutate_in.hxx +46 -4
  103. data/ext/couchbase/protocol/cmd_noop.hxx +82 -0
  104. data/ext/couchbase/protocol/cmd_prepend.hxx +145 -0
  105. data/ext/couchbase/protocol/durability_level.hxx +16 -0
  106. data/ext/couchbase/protocol/hello_feature.hxx +9 -0
  107. data/ext/couchbase/protocol/unsigned_leb128.h +2 -2
  108. data/ext/couchbase/service_type.hxx +1 -1
  109. data/ext/couchbase/version.hxx +18 -4
  110. data/ext/extconf.rb +9 -6
  111. data/ext/test/CMakeLists.txt +5 -0
  112. data/ext/test/test_helper.hxx +3 -3
  113. data/ext/test/test_helper_native.hxx +2 -5
  114. data/ext/test/test_native_binary_operations.cxx +186 -0
  115. data/ext/test/test_native_diagnostics.cxx +54 -3
  116. data/ext/test/test_ruby_trivial_crud.cxx +1 -1
  117. data/lib/couchbase.rb +1 -0
  118. data/lib/couchbase/analytics_options.rb +1 -71
  119. data/lib/couchbase/binary_collection.rb +60 -22
  120. data/lib/couchbase/binary_collection_options.rb +0 -76
  121. data/lib/couchbase/bucket.rb +40 -36
  122. data/lib/couchbase/cluster.rb +89 -156
  123. data/lib/couchbase/collection.rb +290 -72
  124. data/lib/couchbase/collection_options.rb +30 -243
  125. data/lib/couchbase/datastructures/couchbase_list.rb +5 -16
  126. data/lib/couchbase/datastructures/couchbase_map.rb +5 -16
  127. data/lib/couchbase/datastructures/couchbase_queue.rb +5 -16
  128. data/lib/couchbase/datastructures/couchbase_set.rb +5 -16
  129. data/lib/couchbase/diagnostics.rb +181 -0
  130. data/lib/couchbase/json_transcoder.rb +1 -1
  131. data/lib/couchbase/{common_options.rb → logger.rb} +24 -11
  132. data/lib/couchbase/management/query_index_manager.rb +1 -1
  133. data/lib/couchbase/management/user_manager.rb +3 -0
  134. data/lib/couchbase/options.rb +2094 -0
  135. data/lib/couchbase/query_options.rb +1 -144
  136. data/lib/couchbase/scope.rb +8 -25
  137. data/lib/couchbase/search_options.rb +0 -93
  138. data/lib/couchbase/version.rb +20 -1
  139. data/lib/couchbase/view_options.rb +1 -91
  140. metadata +19 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 823424047026c1b6b4c8c61577b4fb51fe93a7be2d14379484ba873e3ee1716c
4
- data.tar.gz: b08989610223adf4ab1e3d5817dece9799be67ffb3b5e5f9b29ba7d7d4f93114
3
+ metadata.gz: 4674765d2d910949acdc81040062ecdcf6b5089297e33bbfc02c3c1cf705b60c
4
+ data.tar.gz: d24c030c9b3a6620d8b7740af911a5b8640f6d98b857719e50df7981a4be46ce
5
5
  SHA512:
6
- metadata.gz: fd82e96988c8d857c63d0ba655aada5315508f88f412556d20d874f4ccc1dbe8e03a31c571d6e2ff7b8ffc6ce2c75b114febc881b3d3aaa728859f527cba8210
7
- data.tar.gz: 766bb40b05dad76df83d85b8a117b4f29d9d9845607ae19ad29c28c59f19f8b8545ae96ba108f5301e1e51dd46c13cac51a8e9424c31c685bc1fed3947c4a6d4
6
+ metadata.gz: 97e0ea2efa94117e1e3738951c86cd1d3176a5304de3e70221916fa3245c96d5d932e10558eb254e06a3047e2adaa3cc97c8e77290876d7422a3d62ecec91fe6
7
+ data.tar.gz: dd31e90a9bf872e1edcc03eab14796122bb201e84a42d7bb68d8630bed55612deb01ebc363465209316d5d2030e210bf404035491f60e259d216240937216b7b
data/README.md CHANGED
@@ -1,11 +1,18 @@
1
- # Couchbase Ruby Client [![gem](https://badge.fury.io/rb/couchbase.svg)](https://rubygems.org/gems/couchbase) [![tests](https://github.com/couchbase/couchbase-ruby-client/workflows/tests/badge.svg)](https://github.com/couchbase/couchbase-ruby-client/actions?query=workflow%3Atests)
1
+ # Couchbase Ruby Client
2
+
3
+ [![license](https://img.shields.io/github/license/couchbase/couchbase-ruby-client?color=brightgreen)](https://opensource.org/licenses/Apache-2.0)
4
+ [![gem](https://img.shields.io/gem/v/couchbase?color=brightgreen)](https://rubygems.org/gems/couchbase)
5
+ [![commits](https://img.shields.io/github/commits-since/couchbase/couchbase-ruby-client/latest?color=brightgreen)](https://github.com/couchbase/couchbase-ruby-client/commits/master)
6
+ [![tests](https://img.shields.io/github/workflow/status/couchbase/couchbase-ruby-client/tests?label=tests)](https://github.com/couchbase/couchbase-ruby-client/actions?query=workflow%3Atests)
7
+ [![linters](https://img.shields.io/github/workflow/status/couchbase/couchbase-ruby-client/linters?label=linters)](https://github.com/couchbase/couchbase-ruby-client/actions?query=workflow%3Alinters)
8
+ [![jenkins](https://img.shields.io/jenkins/build?jobUrl=http%3A%2F%2Fsdk.jenkins.couchbase.com%2Fjob%2Fruby%2Fjob%2Fruby-nightly%2F&label=jenkins)](http://sdk.jenkins.couchbase.com/job/ruby/job/ruby-nightly/)
2
9
 
3
10
  This repository contains the third generation of the official Couchbase SDK for Ruby (aka. SDKv3)
4
11
 
5
12
  ## Support and Feedback
6
13
 
7
- If you find an issue, please file it in [our JIRA issue tracker](https://couchbase.com/issues/browse/RCBC).
8
- Also you are always welcome on [our forum](https://forums.couchbase.com/c/ruby-sdk).
14
+ If you find an issue, please file it in [our JIRA issue tracker](https://couchbase.com/issues/browse/RCBC). Also you are
15
+ always welcome on [our forum](https://forums.couchbase.com/c/ruby-sdk).
9
16
 
10
17
  Please attach version information to ticket/post. To obtain this information use the following command:
11
18
 
@@ -18,7 +25,7 @@ The library tested with the MRI 2.5, 2.6 and 2.7. Supported platforms are Linux
18
25
  Add this line to your application's Gemfile:
19
26
 
20
27
  ```ruby
21
- gem "couchbase", "3.0.1"
28
+ gem "couchbase", "3.0.2"
22
29
  ```
23
30
 
24
31
  And then execute:
@@ -33,6 +40,54 @@ For some platforms we precompile binary packages. When, for some reason, binary
33
40
  `--platform=ruby` to `gem install` command (or check `specific_platform` and `force_ruby_platform` options of Bundler).
34
41
  In latter case, see [Development](#development) section for build dependencies.
35
42
 
43
+ ## Usage
44
+
45
+ Here is a basic steps demonstrating basic operations with data:
46
+
47
+ ```ruby
48
+ require "couchbase"
49
+ include Couchbase # include Couchbase module for brevity
50
+
51
+ # initialize library
52
+ cluster = Cluster.connect("couchbase://127.0.0.1", "Administrator", "password")
53
+
54
+ # open bucket and collection for data operations
55
+ bucket = cluster.bucket("my_bucket")
56
+ collection = bucket.default_collection
57
+
58
+ # update or insert the document
59
+ res = collection.upsert("foo", {"bar" => 42})
60
+ res.cas
61
+ #=> 22120998714646
62
+
63
+ # retrieve document from the collection
64
+ res = collection.get("foo")
65
+ res.cas
66
+ #=> 22120998714646
67
+ res.content
68
+ #=> {"bar"=>42}
69
+
70
+ # remove document
71
+ res = collection.remove("foo")
72
+ res.cas
73
+ #=> 47891154812182
74
+
75
+ # fetch top-3 cities by number of hotels in the collection
76
+ res = cluster.query("
77
+ SELECT city, COUNT(*) AS cnt FROM `travel-sample`
78
+ WHERE type = $type
79
+ GROUP BY city
80
+ ORDER BY cnt DESC
81
+ LIMIT 3",
82
+ Options::Query(named_parameters: {type: "hotel"}, metrics: true))
83
+ res.rows.each do |row|
84
+ p row
85
+ end
86
+ #=> {"city"=>"San Francisco", "cnt"=>132}
87
+ # {"city"=>"London", "cnt"=>67}
88
+ # {"city"=>"Paris", "cnt"=>64}
89
+ ```
90
+
36
91
  ## Development
37
92
 
38
93
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive
@@ -60,3 +115,17 @@ Now the API reference is accessible using web browser (where `VERSION` is curren
60
115
  ## License
61
116
 
62
117
  The gem is available as open source under the terms of the [Apache2 License](https://opensource.org/licenses/Apache-2.0).
118
+
119
+ Copyright 2011-2020 Couchbase, Inc.
120
+
121
+ Licensed under the Apache License, Version 2.0 (the "License");
122
+ you may not use this file except in compliance with the License.
123
+ You may obtain a copy of the License at
124
+
125
+ http://www.apache.org/licenses/LICENSE-2.0
126
+
127
+ Unless required by applicable law or agreed to in writing, software
128
+ distributed under the License is distributed on an "AS IS" BASIS,
129
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130
+ See the License for the specific language governing permissions and
131
+ limitations under the License.
@@ -18,3 +18,5 @@
18
18
  #pragma once
19
19
 
20
20
  #cmakedefine TLS_KEY_LOG_FILE "@TLS_KEY_LOG_FILE@"
21
+ #cmakedefine STATIC_STDLIB 1
22
+ #cmakedefine STATIC_OPENSSL 1
@@ -17,11 +17,14 @@
17
17
 
18
18
  #pragma once
19
19
 
20
- #define BACKEND_BUILD_TIMESTAMP "@BACKEND_BUILD_TIMESTAMP@"
21
- #define BACKEND_CXX_COMPILER "@CMAKE_CXX_COMPILER_ID@ @CMAKE_CXX_COMPILER_VERSION@"
22
- #define BACKEND_C_COMPILER "@CMAKE_C_COMPILER_ID@ @CMAKE_C_COMPILER_VERSION@"
23
- #define BACKEND_SYSTEM "@CMAKE_SYSTEM@"
24
- #define BACKEND_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
25
- #define BACKEND_GIT_REVISION "b59cb40f11ec2dba992eda285eae5cd7238a59c3"
26
- #cmakedefine STATIC_STDLIB 1
27
- #cmakedefine STATIC_OPENSSL 1
20
+ #include <build_config.hxx>
21
+
22
+ namespace couchbase
23
+ {
24
+ constexpr auto BACKEND_BUILD_TIMESTAMP = "@BACKEND_BUILD_TIMESTAMP@";
25
+ constexpr auto BACKEND_CXX_COMPILER = "@CMAKE_CXX_COMPILER_ID@ @CMAKE_CXX_COMPILER_VERSION@";
26
+ constexpr auto BACKEND_C_COMPILER = "@CMAKE_C_COMPILER_ID@ @CMAKE_C_COMPILER_VERSION@";
27
+ constexpr auto BACKEND_SYSTEM = "@CMAKE_SYSTEM@";
28
+ constexpr auto BACKEND_SYSTEM_PROCESSOR = "@CMAKE_SYSTEM_PROCESSOR@";
29
+ constexpr auto BACKEND_GIT_REVISION = "9d2e94b96a3537e8bfc8c9ca88a1c855db6ec977";
30
+ } // namespace couchbase
@@ -1,6 +1,6 @@
1
1
  if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
2
2
  option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF)
3
3
  if(ENABLE_BUILD_WITH_TIME_TRACE)
4
- target_compile_definitions(project_options INTERFACE -ftime-trace)
4
+ target_compile_options(project_options INTERFACE -ftime-trace)
5
5
  endif()
6
6
  endif()
@@ -47,6 +47,11 @@ function(set_project_warnings project_name)
47
47
  -Wnull-dereference # warn if a null dereference is detected
48
48
  -Wdouble-promotion # warn if float is implicit promoted to double
49
49
  -Wformat=2 # warn on security issues around functions that format output (ie printf)
50
+
51
+ # TODO: make it local to ext/couchbase/couchbase.cxx
52
+ -Wno-unknown-warning-option
53
+ -Wno-gnu-statement-expression
54
+ -Wno-compound-token-split-by-macro
50
55
  )
51
56
 
52
57
  if(WARNINGS_AS_ERRORS)
@@ -14,7 +14,7 @@ if(ENABLE_TESTING)
14
14
  include(Catch)
15
15
 
16
16
  macro(ruby_test name)
17
- add_executable(test_ruby_${name} test/test_ruby_${name}.cxx)
17
+ add_executable(test_ruby_${name} "${CMAKE_SOURCE_DIR}/test/test_ruby_${name}.cxx")
18
18
  target_include_directories(test_ruby_${name} PRIVATE ${PROJECT_BINARY_DIR}/generated)
19
19
  target_link_libraries(
20
20
  test_ruby_${name}
@@ -27,7 +27,7 @@ if(ENABLE_TESTING)
27
27
  endmacro()
28
28
 
29
29
  macro(native_test name)
30
- add_executable(test_native_${name} test/test_native_${name}.cxx)
30
+ add_executable(test_native_${name} "${CMAKE_SOURCE_DIR}/test/test_native_${name}.cxx")
31
31
  target_include_directories(test_native_${name} PRIVATE ${PROJECT_BINARY_DIR}/generated)
32
32
  target_link_libraries(
33
33
  test_native_${name}
@@ -45,8 +45,5 @@ if(ENABLE_TESTING)
45
45
  catch_discover_tests(test_native_${name})
46
46
  endmacro()
47
47
 
48
- ruby_test(trivial_crud)
49
- ruby_test(trivial_query)
50
- native_test(trivial_crud)
51
- native_test(diagnostics)
48
+ add_subdirectory(${CMAKE_SOURCE_DIR}/test)
52
49
  endif()
@@ -17,8 +17,8 @@
17
17
 
18
18
  #pragma once
19
19
 
20
- #include <utility>
21
20
  #include <queue>
21
+ #include <utility>
22
22
 
23
23
  #include <operations.hxx>
24
24
  #include <origin.hxx>
@@ -317,6 +317,14 @@ class bucket : public std::enable_shared_from_this<bucket>
317
317
  }
318
318
  }
319
319
 
320
+ template<typename Collector>
321
+ void ping(std::shared_ptr<Collector> collector)
322
+ {
323
+ for (const auto& session : sessions_) {
324
+ session.second->ping(collector->build_reporter());
325
+ }
326
+ }
327
+
320
328
  private:
321
329
  std::string client_id_;
322
330
  asio::io_context& ctx_;
@@ -58,7 +58,7 @@ class MechanismBackend
58
58
  virtual ~MechanismBackend() = default;
59
59
  virtual std::pair<error, std::string_view> start() = 0;
60
60
  virtual std::pair<error, std::string_view> step(std::string_view input) = 0;
61
- virtual std::string_view get_name() const = 0;
61
+ [[nodiscard]] virtual std::string_view get_name() const = 0;
62
62
 
63
63
  protected:
64
64
  const GetUsernameCallback usernameCallback;
@@ -36,6 +36,54 @@
36
36
 
37
37
  namespace couchbase
38
38
  {
39
+ namespace
40
+ {
41
+ class ping_collector : public std::enable_shared_from_this<ping_collector>
42
+ {
43
+ diag::ping_result res_;
44
+ std::function<void(diag::ping_result)> handler_;
45
+ std::atomic_int expected_{ 0 };
46
+ std::mutex mutex_{};
47
+
48
+ public:
49
+ ping_collector(std::string report_id, std::function<void(diag::ping_result)> handler)
50
+ : res_{ std::move(report_id), couchbase::sdk_id() }
51
+ , handler_(std::move(handler))
52
+ {
53
+ }
54
+
55
+ ~ping_collector()
56
+ {
57
+ invoke_handler();
58
+ }
59
+
60
+ [[nodiscard]] diag::ping_result& result()
61
+ {
62
+ return res_;
63
+ }
64
+
65
+ auto build_reporter()
66
+ {
67
+ expected_++;
68
+ return [self = this->shared_from_this()](diag::endpoint_ping_info&& info) {
69
+ std::scoped_lock lock(self->mutex_);
70
+ self->res_.services[info.type].emplace_back(info);
71
+ if (--self->expected_ == 0) {
72
+ self->invoke_handler();
73
+ }
74
+ };
75
+ }
76
+
77
+ void invoke_handler()
78
+ {
79
+ if (handler_ != nullptr) {
80
+ handler_(std::move(res_));
81
+ handler_ = nullptr;
82
+ }
83
+ }
84
+ };
85
+ } // namespace
86
+
39
87
  class cluster
40
88
  {
41
89
  public:
@@ -129,10 +177,7 @@ class cluster
129
177
  report_id = std::make_optional(uuid::to_string(uuid::random()));
130
178
  }
131
179
  asio::post(asio::bind_executor(ctx_, [this, report_id, handler = std::forward<Handler>(handler)]() mutable {
132
- diag::diagnostics_result res{
133
- report_id.value(),
134
- fmt::format("ruby/{}.{}.{}/{}", BACKEND_VERSION_MAJOR, BACKEND_VERSION_MINOR, BACKEND_VERSION_PATCH, BACKEND_GIT_REVISION)
135
- };
180
+ diag::diagnostics_result res{ report_id.value(), couchbase::sdk_id() };
136
181
  if (session_) {
137
182
  res.services[service_type::kv].emplace_back(session_->diag_info());
138
183
  }
@@ -144,6 +189,40 @@ class cluster
144
189
  }));
145
190
  }
146
191
 
192
+ void ping(std::optional<std::string> report_id,
193
+ std::optional<std::string> bucket_name,
194
+ std::set<service_type> services,
195
+ std::function<void(diag::ping_result)> handler)
196
+ {
197
+ if (!report_id) {
198
+ report_id = std::make_optional(uuid::to_string(uuid::random()));
199
+ }
200
+ if (services.empty()) {
201
+ services = { service_type::kv, service_type::views, service_type::query, service_type::search, service_type::analytics };
202
+ }
203
+ asio::post(asio::bind_executor(ctx_, [this, report_id, bucket_name, services, handler = std::move(handler)]() mutable {
204
+ auto collector = std::make_shared<ping_collector>(report_id.value(), std::move(handler));
205
+ if (bucket_name) {
206
+ if (services.find(service_type::kv) != services.end()) {
207
+ auto bucket = buckets_.find(bucket_name.value());
208
+ if (bucket != buckets_.end()) {
209
+ bucket->second->ping(collector);
210
+ }
211
+ }
212
+ } else {
213
+ if (services.find(service_type::kv) != services.end()) {
214
+ if (session_) {
215
+ session_->ping(collector->build_reporter());
216
+ }
217
+ for (auto& bucket : buckets_) {
218
+ bucket.second->ping(collector);
219
+ }
220
+ }
221
+ session_manager_->ping(services, collector, origin_.credentials());
222
+ }
223
+ }));
224
+ }
225
+
147
226
  private:
148
227
  template<typename Handler>
149
228
  void do_dns_srv(Handler&& handler)
@@ -155,7 +234,7 @@ class cluster
155
234
  dns_client_.query_srv(
156
235
  hostname,
157
236
  service,
158
- [hostname, this, handler = std::forward<Handler>(handler)](couchbase::io::dns::dns_client::dns_srv_response resp) mutable {
237
+ [hostname, this, handler = std::forward<Handler>(handler)](couchbase::io::dns::dns_client::dns_srv_response&& resp) mutable {
159
238
  if (resp.ec) {
160
239
  spdlog::warn("failed to fetch DNS SRV records for \"{}\" ({}), assuming that cluster is listening this address",
161
240
  hostname,
@@ -227,7 +306,11 @@ class cluster
227
306
  if (!ec) {
228
307
  if (origin_.options().network == "auto") {
229
308
  origin_.options().network = config.select_network(session_->bootstrap_hostname());
230
- spdlog::info(R"({} detected network is "{}")", session_->log_prefix(), origin_.options().network);
309
+ if (origin_.options().network == "default") {
310
+ spdlog::debug(R"({} detected network is "{}")", session_->log_prefix(), origin_.options().network);
311
+ } else {
312
+ spdlog::info(R"({} detected network is "{}")", session_->log_prefix(), origin_.options().network);
313
+ }
231
314
  }
232
315
  if (origin_.options().network != "default") {
233
316
  origin::node_list nodes;
@@ -17,6 +17,8 @@
17
17
 
18
18
  #pragma once
19
19
 
20
+ #include <set>
21
+
20
22
  #include <gsl/gsl_util>
21
23
 
22
24
  #include <tao/json.hpp>
@@ -15,8 +15,8 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- #include <build_config.hxx>
19
18
  #include <build_info.hxx>
19
+ #include <version.hxx>
20
20
 
21
21
  #include <openssl/crypto.h>
22
22
  #include <asio/version.hpp>
@@ -28,7 +28,6 @@
28
28
 
29
29
  #include <snappy.h>
30
30
 
31
- #include <version.hxx>
32
31
  #include <platform/terminate_handler.h>
33
32
 
34
33
  #include <cluster.hxx>
@@ -63,14 +62,14 @@ init_versions(VALUE mCouchbase)
63
62
  #define VERSION_SPLIT_(VER) (VER) / 100000, (VER) / 100 % 1000, (VER) % 100
64
63
 
65
64
  std::string ver;
66
- ver = fmt::format("{}.{}.{}", BACKEND_VERSION_MAJOR, BACKEND_VERSION_MINOR, BACKEND_VERSION_PATCH);
65
+ ver = fmt::format("{}.{}.{}", couchbase::BACKEND_VERSION_MAJOR, couchbase::BACKEND_VERSION_MINOR, couchbase::BACKEND_VERSION_PATCH);
67
66
  rb_hash_aset(cb_Version, rb_id2sym(rb_intern("backend")), rb_str_freeze(rb_str_new(ver.c_str(), static_cast<long>(ver.size()))));
68
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("build_timestamp")), rb_str_freeze(rb_str_new_cstr(BACKEND_BUILD_TIMESTAMP)));
69
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("revision")), rb_str_freeze(rb_str_new_cstr(BACKEND_GIT_REVISION)));
70
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("platform")), rb_str_freeze(rb_str_new_cstr(BACKEND_SYSTEM)));
71
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cpu")), rb_str_freeze(rb_str_new_cstr(BACKEND_SYSTEM_PROCESSOR)));
72
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cc")), rb_str_freeze(rb_str_new_cstr(BACKEND_C_COMPILER)));
73
- rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cxx")), rb_str_freeze(rb_str_new_cstr(BACKEND_CXX_COMPILER)));
67
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("build_timestamp")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_BUILD_TIMESTAMP)));
68
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("revision")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_GIT_REVISION)));
69
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("platform")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_SYSTEM)));
70
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cpu")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_SYSTEM_PROCESSOR)));
71
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cc")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_C_COMPILER)));
72
+ rb_hash_aset(cb_Version, rb_id2sym(rb_intern("cxx")), rb_str_freeze(rb_str_new_cstr(couchbase::BACKEND_CXX_COMPILER)));
74
73
  #if defined(HAVE_RUBY_VERSION_H)
75
74
  ver = fmt::format("{}.{}.{}", RUBY_API_VERSION_MAJOR, RUBY_API_VERSION_MINOR, RUBY_API_VERSION_TEENY);
76
75
  rb_hash_aset(cb_Version, rb_id2sym(rb_intern("ruby")), rb_str_freeze(rb_str_new(ver.c_str(), static_cast<long>(ver.size()))));
@@ -593,6 +592,7 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE op
593
592
 
594
593
  if (!backend->cluster) {
595
594
  rb_raise(rb_eArgError, "Cluster has been closed already");
595
+ return Qnil;
596
596
  }
597
597
  Check_Type(connection_string, T_STRING);
598
598
  Check_Type(credentials, T_HASH);
@@ -619,6 +619,11 @@ cb_Backend_open(VALUE self, VALUE connection_string, VALUE credentials, VALUE op
619
619
  do {
620
620
  std::string input(RSTRING_PTR(connection_string), static_cast<size_t>(RSTRING_LEN(connection_string)));
621
621
  auto connstr = couchbase::utils::parse_connection_string(input);
622
+ if (connstr.error) {
623
+ exc = rb_exc_new_cstr(eInvalidArgument,
624
+ fmt::format(R"(Failed to parse connection string "{}": {})", input, connstr.error.value()).c_str());
625
+ break;
626
+ }
622
627
  couchbase::cluster_credentials auth{};
623
628
  if (NIL_P(certificate_path) || NIL_P(key_path)) {
624
629
  auth.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
@@ -664,6 +669,7 @@ cb_Backend_diagnostics(VALUE self, VALUE report_id)
664
669
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
665
670
  if (!backend->cluster) {
666
671
  rb_raise(rb_eArgError, "Cluster has been closed already");
672
+ return Qnil;
667
673
  }
668
674
 
669
675
  if (!NIL_P(report_id)) {
@@ -678,7 +684,7 @@ cb_Backend_diagnostics(VALUE self, VALUE report_id)
678
684
  }
679
685
  auto barrier = std::make_shared<std::promise<couchbase::diag::diagnostics_result>>();
680
686
  auto f = barrier->get_future();
681
- backend->cluster->diagnostics(id, [barrier](couchbase::diag::diagnostics_result resp) mutable { barrier->set_value(resp); });
687
+ backend->cluster->diagnostics(id, [barrier](couchbase::diag::diagnostics_result&& resp) mutable { barrier->set_value(resp); });
682
688
  auto resp = f.get();
683
689
 
684
690
  VALUE res = rb_hash_new();
@@ -734,6 +740,10 @@ cb_Backend_diagnostics(VALUE self, VALUE report_id)
734
740
  state = rb_id2sym(rb_intern("disconnecting"));
735
741
  break;
736
742
  }
743
+ if (svc.details) {
744
+ rb_hash_aset(
745
+ service, rb_id2sym(rb_intern("details")), rb_str_new(svc.details->data(), static_cast<long>(svc.details->size())));
746
+ }
737
747
  rb_hash_aset(service, rb_id2sym(rb_intern("state")), state);
738
748
  rb_ary_push(endpoints, service);
739
749
  }
@@ -752,6 +762,7 @@ cb_Backend_open_bucket(VALUE self, VALUE bucket, VALUE wait_until_ready)
752
762
 
753
763
  if (!backend->cluster) {
754
764
  rb_raise(rb_eArgError, "Cluster has been closed already");
765
+ return Qnil;
755
766
  }
756
767
 
757
768
  Check_Type(bucket, T_STRING);
@@ -780,29 +791,467 @@ cb_Backend_open_bucket(VALUE self, VALUE bucket, VALUE wait_until_ready)
780
791
  }
781
792
 
782
793
  template<typename Request>
783
- void
784
- cb__extract_timeout(Request& req, VALUE timeout)
794
+ [[nodiscard]] VALUE
795
+ cb__extract_timeout(Request& req, VALUE options)
796
+ {
797
+ if (!NIL_P(options)) {
798
+ switch (TYPE(options)) {
799
+ case T_HASH:
800
+ return cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
801
+ case T_FIXNUM:
802
+ case T_BIGNUM:
803
+ req.timeout = std::chrono::milliseconds(NUM2ULL(options));
804
+ break;
805
+ default:
806
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
807
+ }
808
+ }
809
+ return Qnil;
810
+ }
811
+
812
+ [[nodiscard]] VALUE
813
+ cb__extract_timeout(std::chrono::milliseconds& timeout, VALUE options)
785
814
  {
786
- if (!NIL_P(timeout)) {
787
- switch (TYPE(timeout)) {
815
+ if (!NIL_P(options)) {
816
+ switch (TYPE(options)) {
817
+ case T_HASH:
818
+ return cb__extract_timeout(timeout, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
788
819
  case T_FIXNUM:
789
820
  case T_BIGNUM:
790
- req.timeout = std::chrono::milliseconds(NUM2ULL(timeout));
821
+ timeout = std::chrono::milliseconds(NUM2ULL(options));
822
+ break;
823
+ default:
824
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("timeout must be an Integer, but given %+" PRIsVALUE, options));
825
+ }
826
+ }
827
+ return Qnil;
828
+ }
829
+
830
+ [[nodiscard]] VALUE
831
+ cb__extract_option_bool(bool& field, VALUE options, const char* name)
832
+ {
833
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
834
+ VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
835
+ if (NIL_P(val)) {
836
+ return Qnil;
837
+ }
838
+ switch (TYPE(val)) {
839
+ case T_TRUE:
840
+ field = true;
841
+ break;
842
+ case T_FALSE:
843
+ field = false;
791
844
  break;
792
845
  default:
793
- rb_raise(rb_eArgError, "timeout must be an Integer");
846
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be a Boolean, but given %+" PRIsVALUE, name, val));
847
+ }
848
+ }
849
+ return Qnil;
850
+ }
851
+
852
+ [[nodiscard]] VALUE
853
+ cb__extract_option_array(VALUE& val, VALUE options, const char* name)
854
+ {
855
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
856
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
857
+ if (NIL_P(val)) {
858
+ return Qnil;
859
+ }
860
+ if (TYPE(val) == T_ARRAY) {
861
+ return Qnil;
862
+ }
863
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Array, but given %+" PRIsVALUE, name, val));
864
+ }
865
+ return Qnil;
866
+ }
867
+
868
+ [[nodiscard]] VALUE
869
+ cb__extract_array_of_ids(std::vector<couchbase::document_id>& ids, VALUE arg)
870
+ {
871
+ if (TYPE(arg) != T_ARRAY) {
872
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Type of IDs argument must be an Array, but given %+" PRIsVALUE, arg));
873
+ }
874
+ auto num_of_ids = static_cast<std::size_t>(RARRAY_LEN(arg));
875
+ if (num_of_ids < 1) {
876
+ rb_raise(rb_eArgError, "Array of IDs must not be empty");
877
+ }
878
+ ids.reserve(num_of_ids);
879
+ for (std::size_t i = 0; i < num_of_ids; ++i) {
880
+ VALUE entry = rb_ary_entry(arg, static_cast<long>(i));
881
+ if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 3) {
882
+ return rb_exc_new_str(
883
+ rb_eArgError, rb_sprintf("ID tuple must be represented as an Array[bucket, collection, id], but given %+" PRIsVALUE, entry));
884
+ }
885
+ VALUE bucket = rb_ary_entry(entry, 0);
886
+ if (TYPE(bucket) != T_STRING) {
887
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Bucket must be a String, but given %+" PRIsVALUE, bucket));
888
+ }
889
+ VALUE collection = rb_ary_entry(entry, 1);
890
+ if (TYPE(collection) != T_STRING) {
891
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Collection must be a String, but given %+" PRIsVALUE, collection));
892
+ }
893
+ VALUE id = rb_ary_entry(entry, 2);
894
+ if (TYPE(id) != T_STRING) {
895
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("ID must be a String, but given %+" PRIsVALUE, id));
896
+ }
897
+ ids.emplace_back(couchbase::document_id{
898
+ std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))),
899
+ std::string(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection))),
900
+ std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))),
901
+ });
902
+ }
903
+
904
+ return Qnil;
905
+ }
906
+
907
+ [[nodiscard]] VALUE
908
+ cb__extract_array_of_id_content(std::vector<std::tuple<couchbase::document_id, std::string, std::uint32_t>>& id_content, VALUE arg)
909
+ {
910
+ if (TYPE(arg) != T_ARRAY) {
911
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Type of ID/content tuples must be an Array, but given %+" PRIsVALUE, arg));
912
+ }
913
+ auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(arg));
914
+ if (num_of_tuples < 1) {
915
+ rb_raise(rb_eArgError, "Array of ID/content tuples must not be empty");
916
+ }
917
+ id_content.reserve(num_of_tuples);
918
+ for (std::size_t i = 0; i < num_of_tuples; ++i) {
919
+ VALUE entry = rb_ary_entry(arg, static_cast<long>(i));
920
+ if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 5) {
921
+ return rb_exc_new_str(
922
+ rb_eArgError,
923
+ rb_sprintf("ID/content tuple must be represented as an Array[bucket, collection, id, content], but given %+" PRIsVALUE,
924
+ entry));
925
+ }
926
+ VALUE bucket = rb_ary_entry(entry, 0);
927
+ if (TYPE(bucket) != T_STRING) {
928
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Bucket must be a String, but given %+" PRIsVALUE, bucket));
929
+ }
930
+ VALUE collection = rb_ary_entry(entry, 1);
931
+ if (TYPE(collection) != T_STRING) {
932
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Collection must be a String, but given %+" PRIsVALUE, collection));
933
+ }
934
+ VALUE id = rb_ary_entry(entry, 2);
935
+ if (TYPE(id) != T_STRING) {
936
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("ID must be a String, but given %+" PRIsVALUE, id));
937
+ }
938
+ VALUE content = rb_ary_entry(entry, 3);
939
+ if (TYPE(content) != T_STRING) {
940
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Content must be a String, but given %+" PRIsVALUE, content));
941
+ }
942
+ VALUE flags = rb_ary_entry(entry, 4);
943
+ if (TYPE(flags) != T_FIXNUM) {
944
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Flags must be an Integer, but given %+" PRIsVALUE, flags));
945
+ }
946
+ id_content.emplace_back(std::make_tuple(
947
+ couchbase::document_id{
948
+ std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))),
949
+ std::string(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection))),
950
+ std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))),
951
+ },
952
+ std::string(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content))),
953
+ FIX2UINT(flags)));
954
+ }
955
+
956
+ return Qnil;
957
+ }
958
+
959
+ [[nodiscard]] VALUE
960
+ cb__extract_array_of_id_cas(std::vector<std::pair<couchbase::document_id, std::uint64_t>>& id_cas, VALUE arg)
961
+ {
962
+ if (TYPE(arg) != T_ARRAY) {
963
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Type of ID/CAS tuples must be an Array, but given %+" PRIsVALUE, arg));
964
+ }
965
+ auto num_of_tuples = static_cast<std::size_t>(RARRAY_LEN(arg));
966
+ if (num_of_tuples < 1) {
967
+ rb_raise(rb_eArgError, "Array of ID/CAS tuples must not be empty");
968
+ }
969
+ id_cas.reserve(num_of_tuples);
970
+ for (std::size_t i = 0; i < num_of_tuples; ++i) {
971
+ VALUE entry = rb_ary_entry(arg, static_cast<long>(i));
972
+ if (TYPE(entry) != T_ARRAY || RARRAY_LEN(entry) != 4) {
973
+ return rb_exc_new_str(
974
+ rb_eArgError,
975
+ rb_sprintf("ID/content tuple must be represented as an Array[bucket, collection, id, CAS], but given %+" PRIsVALUE, entry));
976
+ }
977
+ VALUE bucket = rb_ary_entry(entry, 0);
978
+ if (TYPE(bucket) != T_STRING) {
979
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Bucket must be a String, but given %+" PRIsVALUE, bucket));
980
+ }
981
+ VALUE collection = rb_ary_entry(entry, 1);
982
+ if (TYPE(collection) != T_STRING) {
983
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("Collection must be a String, but given %+" PRIsVALUE, collection));
984
+ }
985
+ VALUE id = rb_ary_entry(entry, 2);
986
+ if (TYPE(id) != T_STRING) {
987
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("ID must be a String, but given %+" PRIsVALUE, id));
988
+ }
989
+ std::uint64_t cas_val = 0;
990
+ VALUE cas = rb_ary_entry(entry, 3);
991
+ if (!NIL_P(cas)) {
992
+ switch (TYPE(cas)) {
993
+ case T_FIXNUM:
994
+ case T_BIGNUM:
995
+ cas_val = NUM2ULL(cas);
996
+ break;
997
+ default:
998
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("CAS must be an Integer or nil, but given %+" PRIsVALUE, cas));
999
+ }
1000
+ }
1001
+
1002
+ id_cas.emplace_back(std::make_pair(
1003
+ couchbase::document_id{
1004
+ std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))),
1005
+ std::string(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection))),
1006
+ std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))),
1007
+ },
1008
+ cas_val));
1009
+ }
1010
+
1011
+ return Qnil;
1012
+ }
1013
+
1014
+ [[nodiscard]] VALUE
1015
+ cb__extract_option_symbol(VALUE& val, VALUE options, const char* name)
1016
+ {
1017
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1018
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1019
+ if (NIL_P(val)) {
1020
+ return Qnil;
1021
+ }
1022
+ if (TYPE(val) == T_SYMBOL) {
1023
+ return Qnil;
1024
+ }
1025
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Symbol, but given %+" PRIsVALUE, name, val));
1026
+ }
1027
+ return Qnil;
1028
+ }
1029
+
1030
+ [[nodiscard]] VALUE
1031
+ cb__extract_option_string(VALUE& val, VALUE options, const char* name)
1032
+ {
1033
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1034
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1035
+ if (NIL_P(val)) {
1036
+ return Qnil;
1037
+ }
1038
+ if (TYPE(val) == T_STRING) {
1039
+ return Qnil;
1040
+ }
1041
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an String, but given %+" PRIsVALUE, name, val));
1042
+ }
1043
+ return Qnil;
1044
+ }
1045
+
1046
+ [[nodiscard]] VALUE
1047
+ cb__extract_option_fixnum(VALUE& val, VALUE options, const char* name)
1048
+ {
1049
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1050
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1051
+ if (NIL_P(val)) {
1052
+ return Qnil;
1053
+ }
1054
+ if (TYPE(val) == T_FIXNUM) {
1055
+ return Qnil;
1056
+ }
1057
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1058
+ }
1059
+ return Qnil;
1060
+ }
1061
+
1062
+ [[nodiscard]] VALUE
1063
+ cb__extract_option_bignum(VALUE& val, VALUE options, const char* name)
1064
+ {
1065
+ if (!NIL_P(options) && TYPE(options) == T_HASH) {
1066
+ val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
1067
+ if (NIL_P(val)) {
1068
+ return Qnil;
1069
+ }
1070
+ switch (TYPE(val)) {
1071
+ case T_FIXNUM:
1072
+ case T_BIGNUM:
1073
+ return Qnil;
1074
+ default:
1075
+ break;
1076
+ }
1077
+ return rb_exc_new_str(rb_eArgError, rb_sprintf("%s must be an Integer, but given %+" PRIsVALUE, name, val));
1078
+ }
1079
+ return Qnil;
1080
+ }
1081
+
1082
+ [[nodiscard]] VALUE
1083
+ cb__extract_durability(couchbase::protocol::durability_level& output_level, std::optional<std::uint16_t>& output_timeout, VALUE options)
1084
+ {
1085
+ VALUE durability_level = Qnil;
1086
+ VALUE exc = cb__extract_option_symbol(durability_level, options, "durability_level");
1087
+ if (!NIL_P(exc)) {
1088
+ return exc;
1089
+ }
1090
+ if (!NIL_P(durability_level)) {
1091
+ ID level = rb_sym2id(durability_level);
1092
+ if (level == rb_intern("none")) {
1093
+ output_level = couchbase::protocol::durability_level::none;
1094
+ } else if (level == rb_intern("majority")) {
1095
+ output_level = couchbase::protocol::durability_level::majority;
1096
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1097
+ output_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1098
+ } else if (level == rb_intern("persist_to_majority")) {
1099
+ output_level = couchbase::protocol::durability_level::persist_to_majority;
1100
+ } else {
1101
+ return rb_exc_new_str(eInvalidArgument, rb_sprintf("unknown durability level: %+" PRIsVALUE, durability_level));
1102
+ }
1103
+ VALUE durability_timeout = Qnil;
1104
+ exc = cb__extract_option_fixnum(durability_timeout, options, "durability_timeout");
1105
+ if (!NIL_P(exc)) {
1106
+ return exc;
794
1107
  }
1108
+ if (!NIL_P(durability_timeout)) {
1109
+ output_timeout = FIX2UINT(durability_timeout);
1110
+ }
1111
+ }
1112
+ return Qnil;
1113
+ }
1114
+
1115
+ template<typename Request>
1116
+ [[nodiscard]] VALUE
1117
+ cb__extract_durability(Request& req, VALUE options)
1118
+ {
1119
+ return cb__extract_durability(req.durability_level, req.durability_timeout, options);
1120
+ }
1121
+
1122
+ static VALUE
1123
+ cb_Backend_ping(VALUE self, VALUE bucket, VALUE options)
1124
+ {
1125
+ cb_backend_data* backend = nullptr;
1126
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1127
+ if (!backend->cluster) {
1128
+ rb_raise(rb_eArgError, "Cluster has been closed already");
1129
+ return Qnil;
1130
+ }
1131
+
1132
+ if (!NIL_P(bucket)) {
1133
+ Check_Type(bucket, T_STRING);
1134
+ }
1135
+
1136
+ if (!NIL_P(options)) {
1137
+ Check_Type(options, T_HASH);
795
1138
  }
1139
+
1140
+ VALUE exc = Qnil;
1141
+ do {
1142
+ VALUE id = Qnil;
1143
+ exc = cb__extract_option_string(id, options, "report_id");
1144
+ if (!NIL_P(exc)) {
1145
+ break;
1146
+ }
1147
+ std::optional<std::string> report_id{};
1148
+ if (!NIL_P(id)) {
1149
+ report_id.emplace(std::string(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id))));
1150
+ }
1151
+ std::optional<std::string> bucket_name{};
1152
+ if (!NIL_P(bucket)) {
1153
+ bucket_name.emplace(std::string(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket))));
1154
+ }
1155
+ VALUE services = Qnil;
1156
+ exc = cb__extract_option_array(services, options, "service_types");
1157
+ if (!NIL_P(exc)) {
1158
+ break;
1159
+ }
1160
+ std::set<couchbase::service_type> selected_services{};
1161
+ if (!NIL_P(services)) {
1162
+ auto entries_num = static_cast<size_t>(RARRAY_LEN(services));
1163
+ for (size_t i = 0; i < entries_num; ++i) {
1164
+ VALUE entry = rb_ary_entry(services, static_cast<long>(i));
1165
+ if (entry == rb_id2sym(rb_intern("kv"))) {
1166
+ selected_services.insert(couchbase::service_type::kv);
1167
+ } else if (entry == rb_id2sym(rb_intern("query"))) {
1168
+ selected_services.insert(couchbase::service_type::query);
1169
+ } else if (entry == rb_id2sym(rb_intern("analytics"))) {
1170
+ selected_services.insert(couchbase::service_type::analytics);
1171
+ } else if (entry == rb_id2sym(rb_intern("search"))) {
1172
+ selected_services.insert(couchbase::service_type::search);
1173
+ } else if (entry == rb_id2sym(rb_intern("views"))) {
1174
+ selected_services.insert(couchbase::service_type::views);
1175
+ }
1176
+ }
1177
+ }
1178
+ auto barrier = std::make_shared<std::promise<couchbase::diag::ping_result>>();
1179
+ auto f = barrier->get_future();
1180
+ backend->cluster->ping(
1181
+ report_id, bucket_name, selected_services, [barrier](couchbase::diag::ping_result&& resp) mutable { barrier->set_value(resp); });
1182
+ auto resp = f.get();
1183
+
1184
+ VALUE res = rb_hash_new();
1185
+ rb_hash_aset(res, rb_id2sym(rb_intern("id")), rb_str_new(resp.id.data(), static_cast<long>(resp.id.size())));
1186
+ rb_hash_aset(res, rb_id2sym(rb_intern("sdk")), rb_str_new(resp.sdk.data(), static_cast<long>(resp.sdk.size())));
1187
+ rb_hash_aset(res, rb_id2sym(rb_intern("version")), INT2FIX(resp.version));
1188
+ services = rb_hash_new();
1189
+ rb_hash_aset(res, rb_id2sym(rb_intern("services")), services);
1190
+ for (const auto& svcs : resp.services) {
1191
+ VALUE type = Qnil;
1192
+ switch (svcs.first) {
1193
+ case couchbase::service_type::kv:
1194
+ type = rb_id2sym(rb_intern("kv"));
1195
+ break;
1196
+ case couchbase::service_type::query:
1197
+ type = rb_id2sym(rb_intern("query"));
1198
+ break;
1199
+ case couchbase::service_type::analytics:
1200
+ type = rb_id2sym(rb_intern("analytics"));
1201
+ break;
1202
+ case couchbase::service_type::search:
1203
+ type = rb_id2sym(rb_intern("search"));
1204
+ break;
1205
+ case couchbase::service_type::views:
1206
+ type = rb_id2sym(rb_intern("views"));
1207
+ break;
1208
+ case couchbase::service_type::management:
1209
+ type = rb_id2sym(rb_intern("mgmt"));
1210
+ break;
1211
+ }
1212
+ VALUE endpoints = rb_ary_new();
1213
+ rb_hash_aset(services, type, endpoints);
1214
+ for (const auto& svc : svcs.second) {
1215
+ VALUE service = rb_hash_new();
1216
+ rb_hash_aset(service, rb_id2sym(rb_intern("latency")), LL2NUM(svc.latency.count()));
1217
+ rb_hash_aset(service, rb_id2sym(rb_intern("id")), rb_str_new(svc.id.data(), static_cast<long>(svc.id.size())));
1218
+ rb_hash_aset(service, rb_id2sym(rb_intern("remote")), rb_str_new(svc.remote.data(), static_cast<long>(svc.remote.size())));
1219
+ rb_hash_aset(service, rb_id2sym(rb_intern("local")), rb_str_new(svc.local.data(), static_cast<long>(svc.local.size())));
1220
+ VALUE state = Qnil;
1221
+ switch (svc.state) {
1222
+ case couchbase::diag::ping_state::ok:
1223
+ state = rb_id2sym(rb_intern("ok"));
1224
+ break;
1225
+ case couchbase::diag::ping_state::timeout:
1226
+ state = rb_id2sym(rb_intern("timeout"));
1227
+ break;
1228
+ case couchbase::diag::ping_state::error:
1229
+ state = rb_id2sym(rb_intern("error"));
1230
+ if (svc.error) {
1231
+ rb_hash_aset(
1232
+ service, rb_id2sym(rb_intern("error")), rb_str_new(svc.error->data(), static_cast<long>(svc.error->size())));
1233
+ }
1234
+ break;
1235
+ }
1236
+ rb_hash_aset(service, rb_id2sym(rb_intern("state")), state);
1237
+ rb_ary_push(endpoints, service);
1238
+ }
1239
+ }
1240
+ return res;
1241
+ } while (false);
1242
+ rb_exc_raise(exc);
1243
+ return Qnil;
796
1244
  }
797
1245
 
798
1246
  static VALUE
799
- cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout)
1247
+ cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
800
1248
  {
801
1249
  cb_backend_data* backend = nullptr;
802
1250
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
803
1251
 
804
1252
  if (!backend->cluster) {
805
1253
  rb_raise(rb_eArgError, "Cluster has been closed already");
1254
+ return Qnil;
806
1255
  }
807
1256
 
808
1257
  Check_Type(bucket, T_STRING);
@@ -817,13 +1266,16 @@ cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id, VA
817
1266
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
818
1267
 
819
1268
  couchbase::operations::get_request req{ doc_id };
820
- cb__extract_timeout(req, timeout);
1269
+ exc = cb__extract_timeout(req, options);
1270
+ if (!NIL_P(exc)) {
1271
+ break;
1272
+ }
821
1273
  auto barrier = std::make_shared<std::promise<couchbase::operations::get_response>>();
822
1274
  auto f = barrier->get_future();
823
- backend->cluster->execute(req, [barrier](couchbase::operations::get_response resp) mutable { barrier->set_value(resp); });
1275
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_response&& resp) mutable { barrier->set_value(resp); });
824
1276
  auto resp = f.get();
825
1277
  if (resp.ec) {
826
- exc = cb__map_error_code(resp.ec, fmt::format("unable fetch {} (opaque={})", doc_id, resp.opaque));
1278
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable fetch "{}" (opaque={}))", doc_id, resp.opaque));
827
1279
  break;
828
1280
  }
829
1281
 
@@ -838,26 +1290,82 @@ cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id, VA
838
1290
  }
839
1291
 
840
1292
  static VALUE
841
- cb_Backend_document_get_projected(VALUE self,
842
- VALUE bucket,
843
- VALUE collection,
844
- VALUE id,
845
- VALUE timeout,
846
- VALUE with_expiry,
847
- VALUE projections,
848
- VALUE preserve_array_indexes)
1293
+ cb_Backend_document_get_multi(VALUE self, VALUE keys, VALUE options)
849
1294
  {
850
1295
  cb_backend_data* backend = nullptr;
851
1296
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
852
1297
 
853
1298
  if (!backend->cluster) {
854
1299
  rb_raise(rb_eArgError, "Cluster has been closed already");
1300
+ return Qnil;
1301
+ }
1302
+
1303
+ VALUE exc = Qnil;
1304
+ do {
1305
+ std::chrono::milliseconds timeout{ 0 };
1306
+ exc = cb__extract_timeout(timeout, options);
1307
+ if (!NIL_P(exc)) {
1308
+ break;
1309
+ }
1310
+
1311
+ std::vector<couchbase::document_id> ids{};
1312
+ exc = cb__extract_array_of_ids(ids, keys);
1313
+ if (!NIL_P(exc)) {
1314
+ break;
1315
+ }
1316
+
1317
+ auto num_of_ids = ids.size();
1318
+ std::vector<std::shared_ptr<std::promise<couchbase::operations::get_response>>> barriers;
1319
+ barriers.reserve(num_of_ids);
1320
+
1321
+ for (auto& id : ids) {
1322
+ couchbase::operations::get_request req{ std::move(id) };
1323
+ if (timeout.count() > 0) {
1324
+ req.timeout = timeout;
1325
+ }
1326
+ auto barrier = std::make_shared<std::promise<couchbase::operations::get_response>>();
1327
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_response&& resp) mutable { barrier->set_value(resp); });
1328
+ barriers.emplace_back(barrier);
1329
+ }
1330
+
1331
+ VALUE res = rb_ary_new_capa(static_cast<long>(num_of_ids));
1332
+ for (auto& barrier : barriers) {
1333
+ auto resp = barrier->get_future().get();
1334
+ VALUE entry = rb_hash_new();
1335
+ if (resp.ec) {
1336
+ rb_hash_aset(entry,
1337
+ rb_id2sym(rb_intern("error")),
1338
+ cb__map_error_code(resp.ec, fmt::format(R"(unable fetch "{}" (opaque={}))", resp.id, resp.opaque)));
1339
+ }
1340
+ rb_hash_aset(entry, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
1341
+ rb_hash_aset(entry, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
1342
+ rb_hash_aset(entry, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
1343
+ rb_ary_push(res, entry);
1344
+ }
1345
+
1346
+ return res;
1347
+ } while (false);
1348
+ rb_exc_raise(exc);
1349
+ return Qnil;
1350
+ }
1351
+
1352
+ static VALUE
1353
+ cb_Backend_document_get_projected(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1354
+ {
1355
+ cb_backend_data* backend = nullptr;
1356
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1357
+
1358
+ if (!backend->cluster) {
1359
+ rb_raise(rb_eArgError, "Cluster has been closed already");
1360
+ return Qnil;
855
1361
  }
856
1362
 
857
1363
  Check_Type(bucket, T_STRING);
858
1364
  Check_Type(collection, T_STRING);
859
1365
  Check_Type(id, T_STRING);
860
-
1366
+ if (!NIL_P(options)) {
1367
+ Check_Type(options, T_HASH);
1368
+ }
861
1369
  VALUE exc = Qnil;
862
1370
  do {
863
1371
  couchbase::document_id doc_id;
@@ -866,12 +1374,29 @@ cb_Backend_document_get_projected(VALUE self,
866
1374
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
867
1375
 
868
1376
  couchbase::operations::get_projected_request req{ doc_id };
869
- cb__extract_timeout(req, timeout);
870
- req.with_expiry = RTEST(with_expiry);
871
- req.preserve_array_indexes = RTEST(preserve_array_indexes);
1377
+ exc = cb__extract_timeout(req, options);
1378
+ if (!NIL_P(exc)) {
1379
+ break;
1380
+ }
1381
+ exc = cb__extract_option_bool(req.with_expiry, options, "with_expiry");
1382
+ if (!NIL_P(exc)) {
1383
+ break;
1384
+ }
1385
+ exc = cb__extract_option_bool(req.preserve_array_indexes, options, "preserve_array_indexes");
1386
+ if (!NIL_P(exc)) {
1387
+ break;
1388
+ }
1389
+ VALUE projections = Qnil;
1390
+ exc = cb__extract_option_array(projections, options, "projections");
1391
+ if (!NIL_P(exc)) {
1392
+ break;
1393
+ }
872
1394
  if (!NIL_P(projections)) {
873
- Check_Type(projections, T_ARRAY);
874
1395
  auto entries_num = static_cast<size_t>(RARRAY_LEN(projections));
1396
+ if (entries_num == 0) {
1397
+ exc = rb_exc_new_cstr(rb_eArgError, "projections array must not be empty");
1398
+ break;
1399
+ }
875
1400
  req.projections.reserve(entries_num);
876
1401
  for (size_t i = 0; i < entries_num; ++i) {
877
1402
  VALUE entry = rb_ary_entry(projections, static_cast<long>(i));
@@ -882,10 +1407,11 @@ cb_Backend_document_get_projected(VALUE self,
882
1407
 
883
1408
  auto barrier = std::make_shared<std::promise<couchbase::operations::get_projected_response>>();
884
1409
  auto f = barrier->get_future();
885
- backend->cluster->execute(req, [barrier](couchbase::operations::get_projected_response resp) mutable { barrier->set_value(resp); });
1410
+ backend->cluster->execute(req,
1411
+ [barrier](couchbase::operations::get_projected_response&& resp) mutable { barrier->set_value(resp); });
886
1412
  auto resp = f.get();
887
1413
  if (resp.ec) {
888
- exc = cb__map_error_code(resp.ec, fmt::format("unable fetch with projections {} (opaque={})", doc_id, resp.opaque));
1414
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable fetch with projections "{}" (opaque={}))", doc_id, resp.opaque));
889
1415
  break;
890
1416
  }
891
1417
 
@@ -903,19 +1429,23 @@ cb_Backend_document_get_projected(VALUE self,
903
1429
  }
904
1430
 
905
1431
  static VALUE
906
- cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE lock_time)
1432
+ cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE lock_time, VALUE options)
907
1433
  {
908
1434
  cb_backend_data* backend = nullptr;
909
1435
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
910
1436
 
911
1437
  if (!backend->cluster) {
912
1438
  rb_raise(rb_eArgError, "Cluster has been closed already");
1439
+ return Qnil;
913
1440
  }
914
1441
 
915
1442
  Check_Type(bucket, T_STRING);
916
1443
  Check_Type(collection, T_STRING);
917
1444
  Check_Type(id, T_STRING);
918
1445
  Check_Type(lock_time, T_FIXNUM);
1446
+ if (!NIL_P(options)) {
1447
+ Check_Type(options, T_HASH);
1448
+ }
919
1449
 
920
1450
  VALUE exc = Qnil;
921
1451
  do {
@@ -925,15 +1455,19 @@ cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VAL
925
1455
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
926
1456
 
927
1457
  couchbase::operations::get_and_lock_request req{ doc_id };
928
- cb__extract_timeout(req, timeout);
1458
+ exc = cb__extract_timeout(req, options);
1459
+ if (!NIL_P(exc)) {
1460
+ break;
1461
+ }
929
1462
  req.lock_time = NUM2UINT(lock_time);
930
1463
 
931
1464
  auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_lock_response>>();
932
1465
  auto f = barrier->get_future();
933
- backend->cluster->execute(req, [barrier](couchbase::operations::get_and_lock_response resp) mutable { barrier->set_value(resp); });
1466
+ backend->cluster->execute(req,
1467
+ [barrier](couchbase::operations::get_and_lock_response&& resp) mutable { barrier->set_value(resp); });
934
1468
  auto resp = f.get();
935
1469
  if (resp.ec) {
936
- exc = cb__map_error_code(resp.ec, fmt::format("unable lock and fetch {} (opaque={})", doc_id, resp.opaque));
1470
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable lock and fetch "{}" (opaque={}))", doc_id, resp.opaque));
937
1471
  break;
938
1472
  }
939
1473
 
@@ -948,19 +1482,23 @@ cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VAL
948
1482
  }
949
1483
 
950
1484
  static VALUE
951
- cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE expiry)
1485
+ cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE expiry, VALUE options)
952
1486
  {
953
1487
  cb_backend_data* backend = nullptr;
954
1488
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
955
1489
 
956
1490
  if (!backend->cluster) {
957
1491
  rb_raise(rb_eArgError, "Cluster has been closed already");
1492
+ return Qnil;
958
1493
  }
959
1494
 
960
1495
  Check_Type(bucket, T_STRING);
961
1496
  Check_Type(collection, T_STRING);
962
1497
  Check_Type(id, T_STRING);
963
1498
  Check_Type(expiry, T_FIXNUM);
1499
+ if (!NIL_P(options)) {
1500
+ Check_Type(options, T_HASH);
1501
+ }
964
1502
 
965
1503
  VALUE exc = Qnil;
966
1504
  do {
@@ -970,15 +1508,19 @@ cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VA
970
1508
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
971
1509
 
972
1510
  couchbase::operations::get_and_touch_request req{ doc_id };
973
- cb__extract_timeout(req, timeout);
1511
+ exc = cb__extract_timeout(req, options);
1512
+ if (!NIL_P(exc)) {
1513
+ break;
1514
+ }
974
1515
  req.expiry = NUM2UINT(expiry);
975
1516
 
976
1517
  auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_touch_response>>();
977
1518
  auto f = barrier->get_future();
978
- backend->cluster->execute(req, [barrier](couchbase::operations::get_and_touch_response resp) mutable { barrier->set_value(resp); });
1519
+ backend->cluster->execute(req,
1520
+ [barrier](couchbase::operations::get_and_touch_response&& resp) mutable { barrier->set_value(resp); });
979
1521
  auto resp = f.get();
980
1522
  if (resp.ec) {
981
- exc = cb__map_error_code(resp.ec, fmt::format("unable fetch and touch {} (opaque={})", doc_id, resp.opaque));
1523
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable fetch and touch "{}" (opaque={}))", doc_id, resp.opaque));
982
1524
  break;
983
1525
  }
984
1526
 
@@ -1010,19 +1552,23 @@ cb__extract_mutation_result(Response resp)
1010
1552
  }
1011
1553
 
1012
1554
  static VALUE
1013
- cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE expiry)
1555
+ cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE expiry, VALUE options)
1014
1556
  {
1015
1557
  cb_backend_data* backend = nullptr;
1016
1558
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1017
1559
 
1018
1560
  if (!backend->cluster) {
1019
1561
  rb_raise(rb_eArgError, "Cluster has been closed already");
1562
+ return Qnil;
1020
1563
  }
1021
1564
 
1022
1565
  Check_Type(bucket, T_STRING);
1023
1566
  Check_Type(collection, T_STRING);
1024
1567
  Check_Type(id, T_STRING);
1025
1568
  Check_Type(expiry, T_FIXNUM);
1569
+ if (!NIL_P(options)) {
1570
+ Check_Type(options, T_HASH);
1571
+ }
1026
1572
 
1027
1573
  VALUE exc = Qnil;
1028
1574
  do {
@@ -1032,15 +1578,18 @@ cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1032
1578
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1033
1579
 
1034
1580
  couchbase::operations::touch_request req{ doc_id };
1035
- cb__extract_timeout(req, timeout);
1581
+ exc = cb__extract_timeout(req, options);
1582
+ if (!NIL_P(exc)) {
1583
+ break;
1584
+ }
1036
1585
  req.expiry = NUM2UINT(expiry);
1037
1586
 
1038
1587
  auto barrier = std::make_shared<std::promise<couchbase::operations::touch_response>>();
1039
1588
  auto f = barrier->get_future();
1040
- backend->cluster->execute(req, [barrier](couchbase::operations::touch_response resp) mutable { barrier->set_value(resp); });
1589
+ backend->cluster->execute(req, [barrier](couchbase::operations::touch_response&& resp) mutable { barrier->set_value(resp); });
1041
1590
  auto resp = f.get();
1042
1591
  if (resp.ec) {
1043
- exc = cb__map_error_code(resp.ec, fmt::format("unable to touch {} (opaque={})", doc_id, resp.opaque));
1592
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to touch "{}" (opaque={}))", doc_id, resp.opaque));
1044
1593
  break;
1045
1594
  }
1046
1595
 
@@ -1053,18 +1602,22 @@ cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1053
1602
  }
1054
1603
 
1055
1604
  static VALUE
1056
- cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout)
1605
+ cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1057
1606
  {
1058
1607
  cb_backend_data* backend = nullptr;
1059
1608
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1060
1609
 
1061
1610
  if (!backend->cluster) {
1062
1611
  rb_raise(rb_eArgError, "Cluster has been closed already");
1612
+ return Qnil;
1063
1613
  }
1064
1614
 
1065
1615
  Check_Type(bucket, T_STRING);
1066
1616
  Check_Type(collection, T_STRING);
1067
1617
  Check_Type(id, T_STRING);
1618
+ if (!NIL_P(options)) {
1619
+ Check_Type(options, T_HASH);
1620
+ }
1068
1621
 
1069
1622
  VALUE exc = Qnil;
1070
1623
  do {
@@ -1074,14 +1627,17 @@ cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1074
1627
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1075
1628
 
1076
1629
  couchbase::operations::exists_request req{ doc_id };
1077
- cb__extract_timeout(req, timeout);
1078
-
1630
+ exc = cb__extract_timeout(req, options);
1631
+ if (!NIL_P(exc)) {
1632
+ break;
1633
+ }
1634
+
1079
1635
  auto barrier = std::make_shared<std::promise<couchbase::operations::exists_response>>();
1080
1636
  auto f = barrier->get_future();
1081
- backend->cluster->execute(req, [barrier](couchbase::operations::exists_response resp) mutable { barrier->set_value(resp); });
1637
+ backend->cluster->execute(req, [barrier](couchbase::operations::exists_response&& resp) mutable { barrier->set_value(resp); });
1082
1638
  auto resp = f.get();
1083
1639
  if (resp.ec) {
1084
- exc = cb__map_error_code(resp.ec, fmt::format("unable to exists {} (opaque={})", doc_id, resp.opaque));
1640
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to exists "{}" (opaque={}))", doc_id, resp.opaque));
1085
1641
  break;
1086
1642
  }
1087
1643
 
@@ -1112,18 +1668,22 @@ cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1112
1668
  }
1113
1669
 
1114
1670
  static VALUE
1115
- cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE cas)
1671
+ cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE cas, VALUE options)
1116
1672
  {
1117
1673
  cb_backend_data* backend = nullptr;
1118
1674
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1119
1675
 
1120
1676
  if (!backend->cluster) {
1121
1677
  rb_raise(rb_eArgError, "Cluster has been closed already");
1678
+ return Qnil;
1122
1679
  }
1123
1680
 
1124
1681
  Check_Type(bucket, T_STRING);
1125
1682
  Check_Type(collection, T_STRING);
1126
1683
  Check_Type(id, T_STRING);
1684
+ if (!NIL_P(options)) {
1685
+ Check_Type(options, T_HASH);
1686
+ }
1127
1687
 
1128
1688
  VALUE exc = Qnil;
1129
1689
  do {
@@ -1133,22 +1693,28 @@ cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1133
1693
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1134
1694
 
1135
1695
  couchbase::operations::unlock_request req{ doc_id };
1136
- cb__extract_timeout(req, timeout);
1696
+ exc = cb__extract_timeout(req, options);
1697
+ if (!NIL_P(exc)) {
1698
+ break;
1699
+ }
1137
1700
  switch (TYPE(cas)) {
1138
1701
  case T_FIXNUM:
1139
1702
  case T_BIGNUM:
1140
1703
  req.cas = NUM2ULL(cas);
1141
1704
  break;
1142
1705
  default:
1143
- rb_raise(rb_eArgError, "CAS must be an Integer");
1706
+ exc = rb_exc_new_str(rb_eArgError, rb_sprintf("CAS must be an Integer, but given %+" PRIsVALUE, cas));
1707
+ }
1708
+ if (!NIL_P(exc)) {
1709
+ break;
1144
1710
  }
1145
1711
 
1146
1712
  auto barrier = std::make_shared<std::promise<couchbase::operations::unlock_response>>();
1147
1713
  auto f = barrier->get_future();
1148
- backend->cluster->execute(req, [barrier](couchbase::operations::unlock_response resp) mutable { barrier->set_value(resp); });
1714
+ backend->cluster->execute(req, [barrier](couchbase::operations::unlock_response&& resp) mutable { barrier->set_value(resp); });
1149
1715
  auto resp = f.get();
1150
1716
  if (resp.ec) {
1151
- exc = cb__map_error_code(resp.ec, fmt::format("unable to unlock {} (opaque={})", doc_id, resp.opaque));
1717
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to unlock "{}" (opaque={}))", doc_id, resp.opaque));
1152
1718
  break;
1153
1719
  }
1154
1720
 
@@ -1161,13 +1727,14 @@ cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1161
1727
  }
1162
1728
 
1163
1729
  static VALUE
1164
- cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
1730
+ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
1165
1731
  {
1166
1732
  cb_backend_data* backend = nullptr;
1167
1733
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1168
1734
 
1169
1735
  if (!backend->cluster) {
1170
1736
  rb_raise(rb_eArgError, "Cluster has been closed already");
1737
+ return Qnil;
1171
1738
  }
1172
1739
 
1173
1740
  Check_Type(bucket, T_STRING);
@@ -1175,6 +1742,9 @@ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1175
1742
  Check_Type(id, T_STRING);
1176
1743
  Check_Type(content, T_STRING);
1177
1744
  Check_Type(flags, T_FIXNUM);
1745
+ if (!NIL_P(options)) {
1746
+ Check_Type(options, T_HASH);
1747
+ }
1178
1748
 
1179
1749
  VALUE exc = Qnil;
1180
1750
  do {
@@ -1185,45 +1755,209 @@ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1185
1755
  std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1186
1756
 
1187
1757
  couchbase::operations::upsert_request req{ doc_id, value };
1188
- cb__extract_timeout(req, timeout);
1758
+ exc = cb__extract_timeout(req, options);
1759
+ if (!NIL_P(exc)) {
1760
+ break;
1761
+ }
1189
1762
  req.flags = FIX2UINT(flags);
1190
1763
 
1191
- if (!NIL_P(options)) {
1192
- Check_Type(options, T_HASH);
1193
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1194
- if (!NIL_P(durability_level)) {
1195
- Check_Type(durability_level, T_SYMBOL);
1196
- ID level = rb_sym2id(durability_level);
1197
- if (level == rb_intern("none")) {
1198
- req.durability_level = couchbase::protocol::durability_level::none;
1199
- } else if (level == rb_intern("majority")) {
1200
- req.durability_level = couchbase::protocol::durability_level::majority;
1201
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1202
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1203
- } else if (level == rb_intern("persist_to_majority")) {
1204
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1205
- } else {
1206
- rb_raise(rb_eArgError, "Unknown durability level");
1207
- }
1208
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1209
- if (!NIL_P(durability_timeout)) {
1210
- Check_Type(durability_timeout, T_FIXNUM);
1211
- req.durability_timeout = FIX2UINT(durability_timeout);
1212
- }
1764
+ exc = cb__extract_durability(req, options);
1765
+ if (!NIL_P(exc)) {
1766
+ break;
1767
+ }
1768
+ VALUE expiry = Qnil;
1769
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
1770
+ if (!NIL_P(exc)) {
1771
+ break;
1772
+ }
1773
+ if (!NIL_P(expiry)) {
1774
+ req.expiry = FIX2UINT(expiry);
1775
+ }
1776
+
1777
+ auto barrier = std::make_shared<std::promise<couchbase::operations::upsert_response>>();
1778
+ auto f = barrier->get_future();
1779
+ backend->cluster->execute(req, [barrier](couchbase::operations::upsert_response&& resp) mutable { barrier->set_value(resp); });
1780
+ auto resp = f.get();
1781
+ if (resp.ec) {
1782
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to upsert "{}" (opaque={}))", doc_id, resp.opaque));
1783
+ break;
1784
+ }
1785
+
1786
+ return cb__extract_mutation_result(resp);
1787
+ } while (false);
1788
+ rb_exc_raise(exc);
1789
+ return Qnil;
1790
+ }
1791
+
1792
+ static VALUE
1793
+ cb_Backend_document_upsert_multi(VALUE self, VALUE id_content, VALUE options)
1794
+ {
1795
+ cb_backend_data* backend = nullptr;
1796
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1797
+
1798
+ if (!backend->cluster) {
1799
+ rb_raise(rb_eArgError, "Cluster has been closed already");
1800
+ return Qnil;
1801
+ }
1802
+
1803
+ VALUE exc = Qnil;
1804
+ do {
1805
+ std::chrono::milliseconds timeout{ 0 };
1806
+ exc = cb__extract_timeout(timeout, options);
1807
+ if (!NIL_P(exc)) {
1808
+ break;
1809
+ }
1810
+
1811
+ couchbase::protocol::durability_level durability_level{ couchbase::protocol::durability_level::none };
1812
+ std::optional<std::uint16_t> durability_timeout{ std::nullopt };
1813
+ exc = cb__extract_durability(durability_level, durability_timeout, options);
1814
+ if (!NIL_P(exc)) {
1815
+ break;
1816
+ }
1817
+ VALUE expiry = Qnil;
1818
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
1819
+ if (!NIL_P(exc)) {
1820
+ break;
1821
+ }
1822
+
1823
+ std::vector<std::tuple<couchbase::document_id, std::string, std::uint32_t>> tuples{};
1824
+ exc = cb__extract_array_of_id_content(tuples, id_content);
1825
+ if (!NIL_P(exc)) {
1826
+ break;
1827
+ }
1828
+
1829
+ auto num_of_tuples = tuples.size();
1830
+ std::vector<std::shared_ptr<std::promise<couchbase::operations::upsert_response>>> barriers;
1831
+ barriers.reserve(num_of_tuples);
1832
+
1833
+ for (auto& tuple : tuples) {
1834
+ couchbase::operations::upsert_request req{ std::move(std::get<0>(tuple)), std::move(std::get<1>(tuple)) };
1835
+ if (timeout.count() > 0) {
1836
+ req.timeout = timeout;
1213
1837
  }
1214
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1838
+ req.flags = std::get<2>(tuple);
1839
+ req.durability_level = durability_level;
1840
+ req.durability_timeout = durability_timeout;
1215
1841
  if (!NIL_P(expiry)) {
1216
- Check_Type(expiry, T_FIXNUM);
1217
1842
  req.expiry = FIX2UINT(expiry);
1218
1843
  }
1844
+ auto barrier = std::make_shared<std::promise<couchbase::operations::upsert_response>>();
1845
+ backend->cluster->execute(req, [barrier](couchbase::operations::upsert_response&& resp) mutable { barrier->set_value(resp); });
1846
+ barriers.emplace_back(barrier);
1219
1847
  }
1220
1848
 
1221
- auto barrier = std::make_shared<std::promise<couchbase::operations::upsert_response>>();
1849
+ VALUE res = rb_ary_new_capa(static_cast<long>(num_of_tuples));
1850
+ for (auto& barrier : barriers) {
1851
+ auto resp = barrier->get_future().get();
1852
+ VALUE entry = cb__extract_mutation_result(resp);
1853
+ if (resp.ec) {
1854
+ rb_hash_aset(entry,
1855
+ rb_id2sym(rb_intern("error")),
1856
+ cb__map_error_code(resp.ec, fmt::format(R"(unable upsert "{}" (opaque={}))", resp.id, resp.opaque)));
1857
+ }
1858
+ rb_ary_push(res, entry);
1859
+ }
1860
+ return res;
1861
+ } while (false);
1862
+ rb_exc_raise(exc);
1863
+ return Qnil;
1864
+ }
1865
+
1866
+ static VALUE
1867
+ cb_Backend_document_append(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE options)
1868
+ {
1869
+ cb_backend_data* backend = nullptr;
1870
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1871
+
1872
+ if (!backend->cluster) {
1873
+ rb_raise(rb_eArgError, "Cluster has been closed already");
1874
+ return Qnil;
1875
+ }
1876
+
1877
+ Check_Type(bucket, T_STRING);
1878
+ Check_Type(collection, T_STRING);
1879
+ Check_Type(id, T_STRING);
1880
+ Check_Type(content, T_STRING);
1881
+ if (!NIL_P(options)) {
1882
+ Check_Type(options, T_HASH);
1883
+ }
1884
+
1885
+ VALUE exc = Qnil;
1886
+ do {
1887
+ couchbase::document_id doc_id;
1888
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1889
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1890
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1891
+ std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1892
+
1893
+ couchbase::operations::append_request req{ doc_id, value };
1894
+ exc = cb__extract_timeout(req, options);
1895
+ if (!NIL_P(exc)) {
1896
+ break;
1897
+ }
1898
+ exc = cb__extract_durability(req, options);
1899
+ if (!NIL_P(exc)) {
1900
+ break;
1901
+ }
1902
+
1903
+ auto barrier = std::make_shared<std::promise<couchbase::operations::append_response>>();
1904
+ auto f = barrier->get_future();
1905
+ backend->cluster->execute(req, [barrier](couchbase::operations::append_response&& resp) mutable { barrier->set_value(resp); });
1906
+ auto resp = f.get();
1907
+ if (resp.ec) {
1908
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to append to "{}" (opaque={}))", doc_id, resp.opaque));
1909
+ break;
1910
+ }
1911
+
1912
+ return cb__extract_mutation_result(resp);
1913
+ } while (false);
1914
+ rb_exc_raise(exc);
1915
+ return Qnil;
1916
+ }
1917
+
1918
+ static VALUE
1919
+ cb_Backend_document_prepend(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE options)
1920
+ {
1921
+ cb_backend_data* backend = nullptr;
1922
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1923
+
1924
+ if (!backend->cluster) {
1925
+ rb_raise(rb_eArgError, "Cluster has been closed already");
1926
+ return Qnil;
1927
+ }
1928
+
1929
+ Check_Type(bucket, T_STRING);
1930
+ Check_Type(collection, T_STRING);
1931
+ Check_Type(id, T_STRING);
1932
+ Check_Type(content, T_STRING);
1933
+ if (!NIL_P(options)) {
1934
+ Check_Type(options, T_HASH);
1935
+ }
1936
+
1937
+ VALUE exc = Qnil;
1938
+ do {
1939
+ couchbase::document_id doc_id;
1940
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1941
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1942
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1943
+ std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1944
+
1945
+ couchbase::operations::prepend_request req{ doc_id, value };
1946
+ exc = cb__extract_timeout(req, options);
1947
+ if (!NIL_P(exc)) {
1948
+ break;
1949
+ }
1950
+ exc = cb__extract_durability(req, options);
1951
+ if (!NIL_P(exc)) {
1952
+ break;
1953
+ }
1954
+
1955
+ auto barrier = std::make_shared<std::promise<couchbase::operations::prepend_response>>();
1222
1956
  auto f = barrier->get_future();
1223
- backend->cluster->execute(req, [barrier](couchbase::operations::upsert_response resp) mutable { barrier->set_value(resp); });
1957
+ backend->cluster->execute(req, [barrier](couchbase::operations::prepend_response&& resp) mutable { barrier->set_value(resp); });
1224
1958
  auto resp = f.get();
1225
1959
  if (resp.ec) {
1226
- exc = cb__map_error_code(resp.ec, fmt::format("unable to upsert {} (opaque={})", doc_id, resp.opaque));
1960
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to prepend to "{}" (opaque={}))", doc_id, resp.opaque));
1227
1961
  break;
1228
1962
  }
1229
1963
 
@@ -1234,13 +1968,14 @@ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1234
1968
  }
1235
1969
 
1236
1970
  static VALUE
1237
- cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
1971
+ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
1238
1972
  {
1239
1973
  cb_backend_data* backend = nullptr;
1240
1974
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1241
1975
 
1242
1976
  if (!backend->cluster) {
1243
1977
  rb_raise(rb_eArgError, "Cluster has been closed already");
1978
+ return Qnil;
1244
1979
  }
1245
1980
 
1246
1981
  Check_Type(bucket, T_STRING);
@@ -1248,6 +1983,9 @@ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id
1248
1983
  Check_Type(id, T_STRING);
1249
1984
  Check_Type(content, T_STRING);
1250
1985
  Check_Type(flags, T_FIXNUM);
1986
+ if (!NIL_P(options)) {
1987
+ Check_Type(options, T_HASH);
1988
+ }
1251
1989
 
1252
1990
  VALUE exc = Qnil;
1253
1991
  do {
@@ -1258,56 +1996,39 @@ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id
1258
1996
  std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1259
1997
 
1260
1998
  couchbase::operations::replace_request req{ doc_id, value };
1261
- cb__extract_timeout(req, timeout);
1999
+ exc = cb__extract_timeout(req, options);
2000
+ if (!NIL_P(exc)) {
2001
+ break;
2002
+ }
1262
2003
  req.flags = FIX2UINT(flags);
1263
2004
 
1264
- if (!NIL_P(options)) {
1265
- Check_Type(options, T_HASH);
1266
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1267
- if (!NIL_P(durability_level)) {
1268
- Check_Type(durability_level, T_SYMBOL);
1269
- ID level = rb_sym2id(durability_level);
1270
- if (level == rb_intern("none")) {
1271
- req.durability_level = couchbase::protocol::durability_level::none;
1272
- } else if (level == rb_intern("majority")) {
1273
- req.durability_level = couchbase::protocol::durability_level::majority;
1274
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1275
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1276
- } else if (level == rb_intern("persist_to_majority")) {
1277
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1278
- } else {
1279
- rb_raise(rb_eArgError, "Unknown durability level");
1280
- }
1281
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1282
- if (!NIL_P(durability_timeout)) {
1283
- Check_Type(durability_timeout, T_FIXNUM);
1284
- req.durability_timeout = FIX2UINT(durability_timeout);
1285
- }
1286
- }
1287
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1288
- if (!NIL_P(expiry)) {
1289
- Check_Type(expiry, T_FIXNUM);
1290
- req.expiry = FIX2UINT(expiry);
1291
- }
1292
- VALUE cas = rb_hash_aref(options, rb_id2sym(rb_intern("cas")));
1293
- if (!NIL_P(cas)) {
1294
- switch (TYPE(cas)) {
1295
- case T_FIXNUM:
1296
- case T_BIGNUM:
1297
- req.cas = NUM2ULL(cas);
1298
- break;
1299
- default:
1300
- rb_raise(rb_eArgError, "CAS must be an Integer");
1301
- }
1302
- }
2005
+ exc = cb__extract_durability(req, options);
2006
+ if (!NIL_P(exc)) {
2007
+ break;
2008
+ }
2009
+ VALUE expiry = Qnil;
2010
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
2011
+ if (!NIL_P(exc)) {
2012
+ break;
2013
+ }
2014
+ if (!NIL_P(expiry)) {
2015
+ req.expiry = FIX2UINT(expiry);
2016
+ }
2017
+ VALUE cas = Qnil;
2018
+ exc = cb__extract_option_bignum(cas, options, "cas");
2019
+ if (!NIL_P(exc)) {
2020
+ break;
2021
+ }
2022
+ if (!NIL_P(cas)) {
2023
+ req.cas = NUM2ULL(cas);
1303
2024
  }
1304
2025
 
1305
2026
  auto barrier = std::make_shared<std::promise<couchbase::operations::replace_response>>();
1306
2027
  auto f = barrier->get_future();
1307
- backend->cluster->execute(req, [barrier](couchbase::operations::replace_response resp) mutable { barrier->set_value(resp); });
2028
+ backend->cluster->execute(req, [barrier](couchbase::operations::replace_response&& resp) mutable { barrier->set_value(resp); });
1308
2029
  auto resp = f.get();
1309
2030
  if (resp.ec) {
1310
- exc = cb__map_error_code(resp.ec, fmt::format("unable to replace {} (opaque={})", doc_id, resp.opaque));
2031
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to replace "{}" (opaque={}))", doc_id, resp.opaque));
1311
2032
  break;
1312
2033
  }
1313
2034
 
@@ -1318,13 +2039,14 @@ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id
1318
2039
  }
1319
2040
 
1320
2041
  static VALUE
1321
- cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
2042
+ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
1322
2043
  {
1323
2044
  cb_backend_data* backend = nullptr;
1324
2045
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1325
2046
 
1326
2047
  if (!backend->cluster) {
1327
2048
  rb_raise(rb_eArgError, "Cluster has been closed already");
2049
+ return Qnil;
1328
2050
  }
1329
2051
 
1330
2052
  Check_Type(bucket, T_STRING);
@@ -1332,6 +2054,9 @@ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1332
2054
  Check_Type(id, T_STRING);
1333
2055
  Check_Type(content, T_STRING);
1334
2056
  Check_Type(flags, T_FIXNUM);
2057
+ if (!NIL_P(options)) {
2058
+ Check_Type(options, T_HASH);
2059
+ }
1335
2060
 
1336
2061
  VALUE exc = Qnil;
1337
2062
  do {
@@ -1342,45 +2067,31 @@ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1342
2067
  std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1343
2068
 
1344
2069
  couchbase::operations::insert_request req{ doc_id, value };
1345
- cb__extract_timeout(req, timeout);
2070
+ exc = cb__extract_timeout(req, options);
2071
+ if (!NIL_P(exc)) {
2072
+ break;
2073
+ }
1346
2074
  req.flags = FIX2UINT(flags);
1347
2075
 
1348
- if (!NIL_P(options)) {
1349
- Check_Type(options, T_HASH);
1350
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1351
- if (!NIL_P(durability_level)) {
1352
- Check_Type(durability_level, T_SYMBOL);
1353
- ID level = rb_sym2id(durability_level);
1354
- if (level == rb_intern("none")) {
1355
- req.durability_level = couchbase::protocol::durability_level::none;
1356
- } else if (level == rb_intern("majority")) {
1357
- req.durability_level = couchbase::protocol::durability_level::majority;
1358
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1359
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1360
- } else if (level == rb_intern("persist_to_majority")) {
1361
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1362
- } else {
1363
- rb_raise(rb_eArgError, "Unknown durability level");
1364
- }
1365
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1366
- if (!NIL_P(durability_timeout)) {
1367
- Check_Type(durability_timeout, T_FIXNUM);
1368
- req.durability_timeout = FIX2UINT(durability_timeout);
1369
- }
1370
- }
1371
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1372
- if (!NIL_P(expiry)) {
1373
- Check_Type(expiry, T_FIXNUM);
1374
- req.expiry = FIX2UINT(expiry);
1375
- }
2076
+ exc = cb__extract_durability(req, options);
2077
+ if (!NIL_P(exc)) {
2078
+ break;
2079
+ }
2080
+ VALUE expiry = Qnil;
2081
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
2082
+ if (!NIL_P(exc)) {
2083
+ break;
2084
+ }
2085
+ if (!NIL_P(expiry)) {
2086
+ req.expiry = FIX2UINT(expiry);
1376
2087
  }
1377
2088
 
1378
2089
  auto barrier = std::make_shared<std::promise<couchbase::operations::insert_response>>();
1379
2090
  auto f = barrier->get_future();
1380
- backend->cluster->execute(req, [barrier](couchbase::operations::insert_response resp) mutable { barrier->set_value(resp); });
2091
+ backend->cluster->execute(req, [barrier](couchbase::operations::insert_response&& resp) mutable { barrier->set_value(resp); });
1381
2092
  auto resp = f.get();
1382
2093
  if (resp.ec) {
1383
- exc = cb__map_error_code(resp.ec, fmt::format("unable to insert {} (opaque={})", doc_id, resp.opaque));
2094
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to insert "{}" (opaque={}))", doc_id, resp.opaque));
1384
2095
  break;
1385
2096
  }
1386
2097
 
@@ -1391,18 +2102,22 @@ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1391
2102
  }
1392
2103
 
1393
2104
  static VALUE
1394
- cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
2105
+ cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1395
2106
  {
1396
2107
  cb_backend_data* backend = nullptr;
1397
2108
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1398
2109
 
1399
2110
  if (!backend->cluster) {
1400
2111
  rb_raise(rb_eArgError, "Cluster has been closed already");
2112
+ return Qnil;
1401
2113
  }
1402
2114
 
1403
2115
  Check_Type(bucket, T_STRING);
1404
2116
  Check_Type(collection, T_STRING);
1405
2117
  Check_Type(id, T_STRING);
2118
+ if (!NIL_P(options)) {
2119
+ Check_Type(options, T_HASH);
2120
+ }
1406
2121
 
1407
2122
  VALUE exc = Qnil;
1408
2123
  do {
@@ -1412,38 +2127,29 @@ cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1412
2127
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1413
2128
 
1414
2129
  couchbase::operations::remove_request req{ doc_id };
1415
- cb__extract_timeout(req, timeout);
1416
- if (!NIL_P(options)) {
1417
- Check_Type(options, T_HASH);
1418
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1419
- if (!NIL_P(durability_level)) {
1420
- Check_Type(durability_level, T_SYMBOL);
1421
- ID level = rb_sym2id(durability_level);
1422
- if (level == rb_intern("none")) {
1423
- req.durability_level = couchbase::protocol::durability_level::none;
1424
- } else if (level == rb_intern("majority")) {
1425
- req.durability_level = couchbase::protocol::durability_level::majority;
1426
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1427
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1428
- } else if (level == rb_intern("persist_to_majority")) {
1429
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1430
- } else {
1431
- rb_raise(rb_eArgError, "Unknown durability level");
1432
- }
1433
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1434
- if (!NIL_P(durability_timeout)) {
1435
- Check_Type(durability_timeout, T_FIXNUM);
1436
- req.durability_timeout = FIX2UINT(durability_timeout);
1437
- }
1438
- }
2130
+ exc = cb__extract_timeout(req, options);
2131
+ if (!NIL_P(exc)) {
2132
+ break;
2133
+ }
2134
+ exc = cb__extract_durability(req, options);
2135
+ if (!NIL_P(exc)) {
2136
+ break;
2137
+ }
2138
+ VALUE cas = Qnil;
2139
+ exc = cb__extract_option_bignum(cas, options, "cas");
2140
+ if (!NIL_P(exc)) {
2141
+ break;
2142
+ }
2143
+ if (!NIL_P(cas)) {
2144
+ req.cas = NUM2ULL(cas);
1439
2145
  }
1440
2146
 
1441
2147
  auto barrier = std::make_shared<std::promise<couchbase::operations::remove_response>>();
1442
2148
  auto f = barrier->get_future();
1443
- backend->cluster->execute(req, [barrier](couchbase::operations::remove_response resp) mutable { barrier->set_value(resp); });
2149
+ backend->cluster->execute(req, [barrier](couchbase::operations::remove_response&& resp) mutable { barrier->set_value(resp); });
1444
2150
  auto resp = f.get();
1445
2151
  if (resp.ec) {
1446
- exc = cb__map_error_code(resp.ec, fmt::format("unable to remove {} (opaque={})", doc_id, resp.opaque));
2152
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to remove "{}" (opaque={}))", doc_id, resp.opaque));
1447
2153
  break;
1448
2154
  }
1449
2155
  return cb__extract_mutation_result(resp);
@@ -1453,18 +2159,93 @@ cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1453
2159
  }
1454
2160
 
1455
2161
  static VALUE
1456
- cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
2162
+ cb_Backend_document_remove_multi(VALUE self, VALUE id_cas, VALUE options)
1457
2163
  {
1458
2164
  cb_backend_data* backend = nullptr;
1459
2165
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1460
2166
 
1461
2167
  if (!backend->cluster) {
1462
2168
  rb_raise(rb_eArgError, "Cluster has been closed already");
2169
+ return Qnil;
2170
+ }
2171
+
2172
+ if (!NIL_P(options)) {
2173
+ Check_Type(options, T_HASH);
2174
+ }
2175
+
2176
+ VALUE exc = Qnil;
2177
+ do {
2178
+ std::chrono::milliseconds timeout{ 0 };
2179
+ exc = cb__extract_timeout(timeout, options);
2180
+ if (!NIL_P(exc)) {
2181
+ break;
2182
+ }
2183
+
2184
+ couchbase::protocol::durability_level durability_level{ couchbase::protocol::durability_level::none };
2185
+ std::optional<std::uint16_t> durability_timeout{ std::nullopt };
2186
+ exc = cb__extract_durability(durability_level, durability_timeout, options);
2187
+ if (!NIL_P(exc)) {
2188
+ break;
2189
+ }
2190
+
2191
+ std::vector<std::pair<couchbase::document_id, std::uint64_t>> tuples{};
2192
+ exc = cb__extract_array_of_id_cas(tuples, id_cas);
2193
+ if (!NIL_P(exc)) {
2194
+ break;
2195
+ }
2196
+
2197
+ auto num_of_tuples = tuples.size();
2198
+ std::vector<std::shared_ptr<std::promise<couchbase::operations::remove_response>>> barriers;
2199
+ barriers.reserve(num_of_tuples);
2200
+
2201
+ for (auto& tuple : tuples) {
2202
+ couchbase::operations::remove_request req{ std::move(tuple.first) };
2203
+ req.cas = tuple.second;
2204
+ if (timeout.count() > 0) {
2205
+ req.timeout = timeout;
2206
+ }
2207
+ req.durability_level = durability_level;
2208
+ req.durability_timeout = durability_timeout;
2209
+ auto barrier = std::make_shared<std::promise<couchbase::operations::remove_response>>();
2210
+ backend->cluster->execute(req, [barrier](couchbase::operations::remove_response&& resp) mutable { barrier->set_value(resp); });
2211
+ barriers.emplace_back(barrier);
2212
+ }
2213
+
2214
+ VALUE res = rb_ary_new_capa(static_cast<long>(num_of_tuples));
2215
+ for (auto& barrier : barriers) {
2216
+ auto resp = barrier->get_future().get();
2217
+ VALUE entry = cb__extract_mutation_result(resp);
2218
+ if (resp.ec) {
2219
+ rb_hash_aset(entry,
2220
+ rb_id2sym(rb_intern("error")),
2221
+ cb__map_error_code(resp.ec, fmt::format(R"(unable remove "{}" (opaque={}))", resp.id, resp.opaque)));
2222
+ }
2223
+ rb_ary_push(res, entry);
2224
+ }
2225
+
2226
+ return res;
2227
+ } while (false);
2228
+ rb_exc_raise(exc);
2229
+ return Qnil;
2230
+ }
2231
+
2232
+ static VALUE
2233
+ cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
2234
+ {
2235
+ cb_backend_data* backend = nullptr;
2236
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
2237
+
2238
+ if (!backend->cluster) {
2239
+ rb_raise(rb_eArgError, "Cluster has been closed already");
2240
+ return Qnil;
1463
2241
  }
1464
2242
 
1465
2243
  Check_Type(bucket, T_STRING);
1466
2244
  Check_Type(collection, T_STRING);
1467
2245
  Check_Type(id, T_STRING);
2246
+ if (!NIL_P(options)) {
2247
+ Check_Type(options, T_HASH);
2248
+ }
1468
2249
 
1469
2250
  VALUE exc = Qnil;
1470
2251
  do {
@@ -1474,65 +2255,45 @@ cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE
1474
2255
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1475
2256
 
1476
2257
  couchbase::operations::increment_request req{ doc_id };
1477
- cb__extract_timeout(req, timeout);
1478
- if (!NIL_P(options)) {
1479
- Check_Type(options, T_HASH);
1480
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1481
- if (!NIL_P(durability_level)) {
1482
- Check_Type(durability_level, T_SYMBOL);
1483
- ID level = rb_sym2id(durability_level);
1484
- if (level == rb_intern("none")) {
1485
- req.durability_level = couchbase::protocol::durability_level::none;
1486
- } else if (level == rb_intern("majority")) {
1487
- req.durability_level = couchbase::protocol::durability_level::majority;
1488
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1489
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1490
- } else if (level == rb_intern("persist_to_majority")) {
1491
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1492
- } else {
1493
- rb_raise(rb_eArgError, "Unknown durability level");
1494
- }
1495
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1496
- if (!NIL_P(durability_timeout)) {
1497
- Check_Type(durability_timeout, T_FIXNUM);
1498
- req.durability_timeout = FIX2UINT(durability_timeout);
1499
- }
1500
- }
1501
- VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1502
- if (!NIL_P(delta)) {
1503
- switch (TYPE(delta)) {
1504
- case T_FIXNUM:
1505
- case T_BIGNUM:
1506
- req.delta = NUM2ULL(delta);
1507
- break;
1508
- default:
1509
- rb_raise(rb_eArgError, "delta must be an Integer");
1510
- }
1511
- }
1512
- VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1513
- if (!NIL_P(initial_value)) {
1514
- switch (TYPE(initial_value)) {
1515
- case T_FIXNUM:
1516
- case T_BIGNUM:
1517
- req.initial_value = NUM2ULL(initial_value);
1518
- break;
1519
- default:
1520
- rb_raise(rb_eArgError, "initial_value must be an Integer");
1521
- }
1522
- }
1523
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1524
- if (!NIL_P(expiry)) {
1525
- Check_Type(expiry, T_FIXNUM);
1526
- req.expiry = FIX2UINT(expiry);
1527
- }
2258
+ exc = cb__extract_timeout(req, options);
2259
+ if (!NIL_P(exc)) {
2260
+ break;
2261
+ }
2262
+ exc = cb__extract_durability(req, options);
2263
+ if (!NIL_P(exc)) {
2264
+ break;
2265
+ }
2266
+ VALUE delta = Qnil;
2267
+ exc = cb__extract_option_bignum(delta, options, "delta");
2268
+ if (!NIL_P(exc)) {
2269
+ break;
2270
+ }
2271
+ if (!NIL_P(delta)) {
2272
+ req.delta = NUM2ULL(delta);
2273
+ }
2274
+ VALUE initial_value = Qnil;
2275
+ exc = cb__extract_option_bignum(initial_value, options, "initial_value");
2276
+ if (!NIL_P(exc)) {
2277
+ break;
2278
+ }
2279
+ if (!NIL_P(initial_value)) {
2280
+ req.initial_value = NUM2ULL(initial_value);
2281
+ }
2282
+ VALUE expiry = Qnil;
2283
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
2284
+ if (!NIL_P(exc)) {
2285
+ break;
2286
+ }
2287
+ if (!NIL_P(expiry)) {
2288
+ req.expiry = FIX2UINT(expiry);
1528
2289
  }
1529
2290
 
1530
2291
  auto barrier = std::make_shared<std::promise<couchbase::operations::increment_response>>();
1531
2292
  auto f = barrier->get_future();
1532
- backend->cluster->execute(req, [barrier](couchbase::operations::increment_response resp) mutable { barrier->set_value(resp); });
2293
+ backend->cluster->execute(req, [barrier](couchbase::operations::increment_response&& resp) mutable { barrier->set_value(resp); });
1533
2294
  auto resp = f.get();
1534
2295
  if (resp.ec) {
1535
- exc = cb__map_error_code(resp.ec, fmt::format("unable to increment {} by {} (opaque={})", doc_id, req.delta, resp.opaque));
2296
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to increment "{}" by {} (opaque={}))", doc_id, req.delta, resp.opaque));
1536
2297
  break;
1537
2298
  }
1538
2299
  VALUE res = cb__extract_mutation_result(resp);
@@ -1544,19 +2305,22 @@ cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE
1544
2305
  }
1545
2306
 
1546
2307
  static VALUE
1547
- cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
2308
+ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1548
2309
  {
1549
2310
  cb_backend_data* backend = nullptr;
1550
2311
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1551
2312
 
1552
2313
  if (!backend->cluster) {
1553
2314
  rb_raise(rb_eArgError, "Cluster has been closed already");
2315
+ return Qnil;
1554
2316
  }
1555
2317
 
1556
2318
  Check_Type(bucket, T_STRING);
1557
2319
  Check_Type(collection, T_STRING);
1558
2320
  Check_Type(id, T_STRING);
1559
- Check_Type(options, T_HASH);
2321
+ if (!NIL_P(options)) {
2322
+ Check_Type(options, T_HASH);
2323
+ }
1560
2324
 
1561
2325
  VALUE exc = Qnil;
1562
2326
  do {
@@ -1566,65 +2330,45 @@ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE
1566
2330
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1567
2331
 
1568
2332
  couchbase::operations::decrement_request req{ doc_id };
1569
- cb__extract_timeout(req, timeout);
1570
- if (!NIL_P(options)) {
1571
- Check_Type(options, T_HASH);
1572
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1573
- if (!NIL_P(durability_level)) {
1574
- Check_Type(durability_level, T_SYMBOL);
1575
- ID level = rb_sym2id(durability_level);
1576
- if (level == rb_intern("none")) {
1577
- req.durability_level = couchbase::protocol::durability_level::none;
1578
- } else if (level == rb_intern("majority")) {
1579
- req.durability_level = couchbase::protocol::durability_level::majority;
1580
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1581
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1582
- } else if (level == rb_intern("persist_to_majority")) {
1583
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1584
- } else {
1585
- rb_raise(rb_eArgError, "Unknown durability level");
1586
- }
1587
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1588
- if (!NIL_P(durability_timeout)) {
1589
- Check_Type(durability_timeout, T_FIXNUM);
1590
- req.durability_timeout = FIX2UINT(durability_timeout);
1591
- }
1592
- }
1593
- VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1594
- if (!NIL_P(delta)) {
1595
- switch (TYPE(delta)) {
1596
- case T_FIXNUM:
1597
- case T_BIGNUM:
1598
- req.delta = NUM2ULL(delta);
1599
- break;
1600
- default:
1601
- rb_raise(rb_eArgError, "delta must be an Integer");
1602
- }
1603
- }
1604
- VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1605
- if (!NIL_P(initial_value)) {
1606
- switch (TYPE(initial_value)) {
1607
- case T_FIXNUM:
1608
- case T_BIGNUM:
1609
- req.initial_value = NUM2ULL(initial_value);
1610
- break;
1611
- default:
1612
- rb_raise(rb_eArgError, "initial_value must be an Integer");
1613
- }
1614
- }
1615
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1616
- if (!NIL_P(expiry)) {
1617
- Check_Type(expiry, T_FIXNUM);
1618
- req.expiry = FIX2UINT(expiry);
1619
- }
2333
+ exc = cb__extract_timeout(req, options);
2334
+ if (!NIL_P(exc)) {
2335
+ break;
2336
+ }
2337
+ exc = cb__extract_durability(req, options);
2338
+ if (!NIL_P(exc)) {
2339
+ break;
2340
+ }
2341
+ VALUE delta = Qnil;
2342
+ exc = cb__extract_option_bignum(delta, options, "delta");
2343
+ if (!NIL_P(exc)) {
2344
+ break;
2345
+ }
2346
+ if (!NIL_P(delta)) {
2347
+ req.delta = NUM2ULL(delta);
2348
+ }
2349
+ VALUE initial_value = Qnil;
2350
+ exc = cb__extract_option_bignum(initial_value, options, "initial_value");
2351
+ if (!NIL_P(exc)) {
2352
+ break;
2353
+ }
2354
+ if (!NIL_P(initial_value)) {
2355
+ req.initial_value = NUM2ULL(initial_value);
2356
+ }
2357
+ VALUE expiry = Qnil;
2358
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
2359
+ if (!NIL_P(exc)) {
2360
+ break;
2361
+ }
2362
+ if (!NIL_P(expiry)) {
2363
+ req.expiry = FIX2UINT(expiry);
1620
2364
  }
1621
2365
 
1622
2366
  auto barrier = std::make_shared<std::promise<couchbase::operations::decrement_response>>();
1623
2367
  auto f = barrier->get_future();
1624
- backend->cluster->execute(req, [barrier](couchbase::operations::decrement_response resp) mutable { barrier->set_value(resp); });
2368
+ backend->cluster->execute(req, [barrier](couchbase::operations::decrement_response&& resp) mutable { barrier->set_value(resp); });
1625
2369
  auto resp = f.get();
1626
2370
  if (resp.ec) {
1627
- exc = cb__map_error_code(resp.ec, fmt::format("unable to decrement {} by {} (opaque={})", doc_id, req.delta, resp.opaque));
2371
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to decrement "{}" by {} (opaque={}))", doc_id, req.delta, resp.opaque));
1628
2372
  break;
1629
2373
  }
1630
2374
  VALUE res = cb__extract_mutation_result(resp);
@@ -1680,6 +2424,9 @@ cb__map_subdoc_opcode(couchbase::protocol::subdoc_opcode opcode)
1680
2424
 
1681
2425
  case couchbase::protocol::subdoc_opcode::set_doc:
1682
2426
  return rb_id2sym(rb_intern("set_doc"));
2427
+
2428
+ case couchbase::protocol::subdoc_opcode::replace_body_with_xattr:
2429
+ return rb_id2sym(rb_intern("replace_body_with_xattr"));
1683
2430
  }
1684
2431
  return rb_id2sym(rb_intern("unknown"));
1685
2432
  }
@@ -1807,13 +2554,14 @@ cb__map_subdoc_status(couchbase::protocol::status status, std::size_t index, con
1807
2554
  }
1808
2555
 
1809
2556
  static VALUE
1810
- cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE access_deleted, VALUE specs)
2557
+ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE specs, VALUE options)
1811
2558
  {
1812
2559
  cb_backend_data* backend = nullptr;
1813
2560
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1814
2561
 
1815
2562
  if (!backend->cluster) {
1816
2563
  rb_raise(rb_eArgError, "Cluster has been closed already");
2564
+ return Qnil;
1817
2565
  }
1818
2566
 
1819
2567
  Check_Type(bucket, T_STRING);
@@ -1822,6 +2570,10 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1822
2570
  Check_Type(specs, T_ARRAY);
1823
2571
  if (RARRAY_LEN(specs) <= 0) {
1824
2572
  rb_raise(rb_eArgError, "Array with specs cannot be empty");
2573
+ return Qnil;
2574
+ }
2575
+ if (!NIL_P(options)) {
2576
+ Check_Type(options, T_HASH);
1825
2577
  }
1826
2578
 
1827
2579
  VALUE exc = Qnil;
@@ -1832,8 +2584,14 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1832
2584
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1833
2585
 
1834
2586
  couchbase::operations::lookup_in_request req{ doc_id };
1835
- cb__extract_timeout(req, timeout);
1836
- req.access_deleted = RTEST(access_deleted);
2587
+ exc = cb__extract_timeout(req, options);
2588
+ if (!NIL_P(exc)) {
2589
+ break;
2590
+ }
2591
+ exc = cb__extract_option_bool(req.access_deleted, options, "access_deleted");
2592
+ if (!NIL_P(exc)) {
2593
+ break;
2594
+ }
1837
2595
  auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1838
2596
  req.specs.entries.reserve(entries_size);
1839
2597
  for (size_t i = 0; i < entries_size; ++i) {
@@ -1852,20 +2610,24 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1852
2610
  } else if (operation_id == rb_intern("count")) {
1853
2611
  opcode = couchbase::protocol::subdoc_opcode::get_count;
1854
2612
  } else {
1855
- rb_raise(rb_eArgError, "Unsupported operation for subdocument lookup");
2613
+ exc = rb_exc_new_str(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
2614
+ break;
1856
2615
  }
1857
2616
  bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
1858
2617
  VALUE path = rb_hash_aref(entry, rb_id2sym(rb_intern("path")));
1859
2618
  Check_Type(path, T_STRING);
1860
2619
  req.specs.add_spec(opcode, xattr, std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))));
1861
2620
  }
2621
+ if (!NIL_P(exc)) {
2622
+ break;
2623
+ }
1862
2624
 
1863
2625
  auto barrier = std::make_shared<std::promise<couchbase::operations::lookup_in_response>>();
1864
2626
  auto f = barrier->get_future();
1865
- backend->cluster->execute(req, [barrier](couchbase::operations::lookup_in_response resp) mutable { barrier->set_value(resp); });
2627
+ backend->cluster->execute(req, [barrier](couchbase::operations::lookup_in_response&& resp) mutable { barrier->set_value(resp); });
1866
2628
  auto resp = f.get();
1867
2629
  if (resp.ec) {
1868
- exc = cb__map_error_code(resp.ec, fmt::format("unable fetch {} (opaque={})", doc_id, resp.opaque));
2630
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable fetch "{}" (opaque={}))", doc_id, resp.opaque));
1869
2631
  break;
1870
2632
  }
1871
2633
 
@@ -1873,6 +2635,9 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1873
2635
  rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
1874
2636
  VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
1875
2637
  rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
2638
+ if (resp.deleted) {
2639
+ rb_hash_aset(res, rb_id2sym(rb_intern("deleted")), Qtrue);
2640
+ }
1876
2641
  for (size_t i = 0; i < resp.fields.size(); ++i) {
1877
2642
  VALUE entry = rb_hash_new();
1878
2643
  rb_hash_aset(entry, rb_id2sym(rb_intern("index")), ULL2NUM(i));
@@ -1897,13 +2662,14 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1897
2662
  }
1898
2663
 
1899
2664
  static VALUE
1900
- cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE specs, VALUE options)
2665
+ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE specs, VALUE options)
1901
2666
  {
1902
2667
  cb_backend_data* backend = nullptr;
1903
2668
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
1904
2669
 
1905
2670
  if (!backend->cluster) {
1906
2671
  rb_raise(rb_eArgError, "Cluster has been closed already");
2672
+ return Qnil;
1907
2673
  }
1908
2674
 
1909
2675
  Check_Type(bucket, T_STRING);
@@ -1912,6 +2678,10 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1912
2678
  Check_Type(specs, T_ARRAY);
1913
2679
  if (RARRAY_LEN(specs) <= 0) {
1914
2680
  rb_raise(rb_eArgError, "Array with specs cannot be empty");
2681
+ return Qnil;
2682
+ }
2683
+ if (!NIL_P(options)) {
2684
+ Check_Type(options, T_HASH);
1915
2685
  }
1916
2686
 
1917
2687
  VALUE exc = Qnil;
@@ -1922,62 +2692,50 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1922
2692
  doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1923
2693
 
1924
2694
  couchbase::operations::mutate_in_request req{ doc_id };
1925
- cb__extract_timeout(req, timeout);
1926
- if (!NIL_P(options)) {
1927
- Check_Type(options, T_HASH);
1928
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1929
- if (!NIL_P(durability_level)) {
1930
- Check_Type(durability_level, T_SYMBOL);
1931
- ID level = rb_sym2id(durability_level);
1932
- if (level == rb_intern("none")) {
1933
- req.durability_level = couchbase::protocol::durability_level::none;
1934
- } else if (level == rb_intern("majority")) {
1935
- req.durability_level = couchbase::protocol::durability_level::majority;
1936
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1937
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1938
- } else if (level == rb_intern("persist_to_majority")) {
1939
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1940
- } else {
1941
- rb_raise(rb_eArgError, "Unknown durability level");
1942
- }
1943
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1944
- if (!NIL_P(durability_timeout)) {
1945
- Check_Type(durability_timeout, T_FIXNUM);
1946
- req.durability_timeout = FIX2UINT(durability_timeout);
1947
- }
1948
- }
1949
- VALUE access_deleted = rb_hash_aref(options, rb_id2sym(rb_intern("access_deleted")));
1950
- if (!NIL_P(access_deleted)) {
1951
- req.access_deleted = RTEST(access_deleted);
1952
- }
1953
- VALUE store_semantics = rb_hash_aref(options, rb_id2sym(rb_intern("store_semantics")));
1954
- if (!NIL_P(store_semantics)) {
1955
- Check_Type(store_semantics, T_SYMBOL);
1956
- ID semantics = rb_sym2id(store_semantics);
1957
- if (semantics == rb_intern("replace")) {
1958
- req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::replace;
1959
- } else if (semantics == rb_intern("insert")) {
1960
- req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::insert;
1961
- } else if (semantics == rb_intern("upsert")) {
1962
- req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::upsert;
1963
- }
1964
- }
1965
- VALUE expiry = rb_hash_aref(options, rb_id2sym(rb_intern("expiry")));
1966
- if (!NIL_P(expiry)) {
1967
- Check_Type(expiry, T_FIXNUM);
1968
- req.expiry = FIX2UINT(expiry);
1969
- }
1970
- VALUE cas = rb_hash_aref(options, rb_id2sym(rb_intern("cas")));
1971
- if (!NIL_P(cas)) {
1972
- switch (TYPE(cas)) {
1973
- case T_FIXNUM:
1974
- case T_BIGNUM:
1975
- req.cas = NUM2ULL(cas);
1976
- break;
1977
- default:
1978
- rb_raise(rb_eArgError, "CAS must be an Integer");
1979
- }
1980
- }
2695
+ exc = cb__extract_timeout(req, options);
2696
+ if (!NIL_P(exc)) {
2697
+ break;
2698
+ }
2699
+ exc = cb__extract_durability(req, options);
2700
+ if (!NIL_P(exc)) {
2701
+ break;
2702
+ }
2703
+ VALUE cas = Qnil;
2704
+ exc = cb__extract_option_bignum(cas, options, "cas");
2705
+ if (!NIL_P(exc)) {
2706
+ break;
2707
+ }
2708
+ if (!NIL_P(cas)) {
2709
+ req.cas = NUM2ULL(cas);
2710
+ }
2711
+ VALUE expiry = Qnil;
2712
+ exc = cb__extract_option_fixnum(expiry, options, "expiry");
2713
+ if (!NIL_P(exc)) {
2714
+ break;
2715
+ }
2716
+ if (!NIL_P(expiry)) {
2717
+ req.expiry = FIX2UINT(expiry);
2718
+ }
2719
+ exc = cb__extract_option_bool(req.access_deleted, options, "access_deleted");
2720
+ if (!NIL_P(exc)) {
2721
+ break;
2722
+ }
2723
+ exc = cb__extract_option_bool(req.create_as_deleted, options, "create_as_deleted");
2724
+ if (!NIL_P(exc)) {
2725
+ break;
2726
+ }
2727
+ VALUE store_semantics = Qnil;
2728
+ exc = cb__extract_option_symbol(store_semantics, options, "store_semantics");
2729
+ if (!NIL_P(exc)) {
2730
+ break;
2731
+ }
2732
+ ID semantics = rb_sym2id(store_semantics);
2733
+ if (semantics == rb_intern("replace")) {
2734
+ req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::replace;
2735
+ } else if (semantics == rb_intern("insert")) {
2736
+ req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::insert;
2737
+ } else if (semantics == rb_intern("upsert")) {
2738
+ req.store_semantics = couchbase::protocol::mutate_in_request_body::store_semantics_type::upsert;
1981
2739
  }
1982
2740
  auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1983
2741
  req.specs.entries.reserve(entries_size);
@@ -2009,7 +2767,9 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
2009
2767
  } else if (operation_id == rb_intern("set_doc")) {
2010
2768
  opcode = couchbase::protocol::subdoc_opcode::set_doc;
2011
2769
  } else {
2012
- rb_raise(rb_eArgError, "Unsupported operation for subdocument mutation: %+" PRIsVALUE, operation);
2770
+ exc =
2771
+ rb_exc_new_str(eInvalidArgument, rb_sprintf("unsupported operation for subdocument mutation: %+" PRIsVALUE, operation));
2772
+ break;
2013
2773
  }
2014
2774
  bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
2015
2775
  bool create_path = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("create_path"))));
@@ -2037,13 +2797,16 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
2037
2797
  std::string(RSTRING_PTR(param), static_cast<size_t>(RSTRING_LEN(param))));
2038
2798
  }
2039
2799
  }
2800
+ if (!NIL_P(exc)) {
2801
+ break;
2802
+ }
2040
2803
 
2041
2804
  auto barrier = std::make_shared<std::promise<couchbase::operations::mutate_in_response>>();
2042
2805
  auto f = barrier->get_future();
2043
- backend->cluster->execute(req, [barrier](couchbase::operations::mutate_in_response resp) mutable { barrier->set_value(resp); });
2806
+ backend->cluster->execute(req, [barrier](couchbase::operations::mutate_in_response&& resp) mutable { barrier->set_value(resp); });
2044
2807
  auto resp = f.get();
2045
2808
  if (resp.ec) {
2046
- exc = cb__map_error_code(resp.ec, fmt::format("unable to mutate {} (opaque={})", doc_id, resp.opaque));
2809
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to mutate "{}" (opaque={}))", doc_id, resp.opaque));
2047
2810
  break;
2048
2811
  }
2049
2812
 
@@ -2051,6 +2814,9 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
2051
2814
  if (resp.first_error_index) {
2052
2815
  rb_hash_aset(res, rb_id2sym(rb_intern("first_error_index")), ULONG2NUM(resp.first_error_index.value()));
2053
2816
  }
2817
+ if (resp.deleted) {
2818
+ rb_hash_aset(res, rb_id2sym(rb_intern("deleted")), Qtrue);
2819
+ }
2054
2820
  VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
2055
2821
  rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
2056
2822
  for (size_t i = 0; i < resp.fields.size(); ++i) {
@@ -2100,6 +2866,7 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
2100
2866
 
2101
2867
  if (!backend->cluster) {
2102
2868
  rb_raise(rb_eArgError, "Cluster has been closed already");
2869
+ return Qnil;
2103
2870
  }
2104
2871
 
2105
2872
  Check_Type(statement, T_STRING);
@@ -2114,7 +2881,10 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
2114
2881
  Check_Type(client_context_id, T_STRING);
2115
2882
  req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
2116
2883
  }
2117
- cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
2884
+ exc = cb__extract_timeout(req, options);
2885
+ if (!NIL_P(exc)) {
2886
+ break;
2887
+ }
2118
2888
  VALUE adhoc = rb_hash_aref(options, rb_id2sym(rb_intern("adhoc")));
2119
2889
  if (!NIL_P(adhoc)) {
2120
2890
  req.adhoc = RTEST(adhoc);
@@ -2250,7 +3020,7 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
2250
3020
 
2251
3021
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_response>>();
2252
3022
  auto f = barrier->get_future();
2253
- backend->cluster->execute_http(req, [barrier](couchbase::operations::query_response resp) mutable { barrier->set_value(resp); });
3023
+ backend->cluster->execute_http(req, [barrier](couchbase::operations::query_response&& resp) mutable { barrier->set_value(resp); });
2254
3024
  auto resp = f.get();
2255
3025
  if (resp.ec) {
2256
3026
  if (resp.payload.meta_data.errors && !resp.payload.meta_data.errors->empty()) {
@@ -2441,6 +3211,7 @@ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
2441
3211
 
2442
3212
  if (!backend->cluster) {
2443
3213
  rb_raise(rb_eArgError, "Cluster has been closed already");
3214
+ return Qnil;
2444
3215
  }
2445
3216
 
2446
3217
  Check_Type(bucket_settings, T_HASH);
@@ -2448,12 +3219,15 @@ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
2448
3219
  VALUE exc = Qnil;
2449
3220
  do {
2450
3221
  couchbase::operations::bucket_create_request req{};
2451
- cb__extract_timeout(req, timeout);
3222
+ exc = cb__extract_timeout(req, timeout);
3223
+ if (!NIL_P(exc)) {
3224
+ break;
3225
+ }
2452
3226
  cb__generate_bucket_settings(bucket_settings, req.bucket, true);
2453
3227
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_create_response>>();
2454
3228
  auto f = barrier->get_future();
2455
- backend->cluster->execute_http(req,
2456
- [barrier](couchbase::operations::bucket_create_response resp) mutable { barrier->set_value(resp); });
3229
+ backend->cluster->execute_http(
3230
+ req, [barrier](couchbase::operations::bucket_create_response&& resp) mutable { barrier->set_value(resp); });
2457
3231
  auto resp = f.get();
2458
3232
  if (resp.ec) {
2459
3233
  exc = cb__map_error_code(
@@ -2475,18 +3249,22 @@ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE timeout)
2475
3249
 
2476
3250
  if (!backend->cluster) {
2477
3251
  rb_raise(rb_eArgError, "Cluster has been closed already");
3252
+ return Qnil;
2478
3253
  }
2479
3254
 
2480
3255
  Check_Type(bucket_settings, T_HASH);
2481
3256
  VALUE exc = Qnil;
2482
3257
  do {
2483
3258
  couchbase::operations::bucket_update_request req{};
2484
- cb__extract_timeout(req, timeout);
3259
+ exc = cb__extract_timeout(req, timeout);
3260
+ if (!NIL_P(exc)) {
3261
+ break;
3262
+ }
2485
3263
  cb__generate_bucket_settings(bucket_settings, req.bucket, false);
2486
3264
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_update_response>>();
2487
3265
  auto f = barrier->get_future();
2488
- backend->cluster->execute_http(req,
2489
- [barrier](couchbase::operations::bucket_update_response resp) mutable { barrier->set_value(resp); });
3266
+ backend->cluster->execute_http(
3267
+ req, [barrier](couchbase::operations::bucket_update_response&& resp) mutable { barrier->set_value(resp); });
2490
3268
  auto resp = f.get();
2491
3269
  if (resp.ec) {
2492
3270
  exc = cb__map_error_code(
@@ -2507,6 +3285,7 @@ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
2507
3285
 
2508
3286
  if (!backend->cluster) {
2509
3287
  rb_raise(rb_eArgError, "Cluster has been closed already");
3288
+ return Qnil;
2510
3289
  }
2511
3290
 
2512
3291
  Check_Type(bucket_name, T_STRING);
@@ -2514,12 +3293,15 @@ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
2514
3293
  VALUE exc = Qnil;
2515
3294
  do {
2516
3295
  couchbase::operations::bucket_drop_request req{};
2517
- cb__extract_timeout(req, timeout);
3296
+ exc = cb__extract_timeout(req, timeout);
3297
+ if (!NIL_P(exc)) {
3298
+ break;
3299
+ }
2518
3300
  req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2519
3301
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_drop_response>>();
2520
3302
  auto f = barrier->get_future();
2521
3303
  backend->cluster->execute_http(req,
2522
- [barrier](couchbase::operations::bucket_drop_response resp) mutable { barrier->set_value(resp); });
3304
+ [barrier](couchbase::operations::bucket_drop_response&& resp) mutable { barrier->set_value(resp); });
2523
3305
  auto resp = f.get();
2524
3306
  if (resp.ec) {
2525
3307
  exc = cb__map_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
@@ -2539,6 +3321,7 @@ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE timeout)
2539
3321
 
2540
3322
  if (!backend->cluster) {
2541
3323
  rb_raise(rb_eArgError, "Cluster has been closed already");
3324
+ return Qnil;
2542
3325
  }
2543
3326
 
2544
3327
  Check_Type(bucket_name, T_STRING);
@@ -2546,12 +3329,15 @@ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE timeout)
2546
3329
  VALUE exc = Qnil;
2547
3330
  do {
2548
3331
  couchbase::operations::bucket_flush_request req{};
2549
- cb__extract_timeout(req, timeout);
3332
+ exc = cb__extract_timeout(req, timeout);
3333
+ if (!NIL_P(exc)) {
3334
+ break;
3335
+ }
2550
3336
  req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2551
3337
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_flush_response>>();
2552
3338
  auto f = barrier->get_future();
2553
- backend->cluster->execute_http(req,
2554
- [barrier](couchbase::operations::bucket_flush_response resp) mutable { barrier->set_value(resp); });
3339
+ backend->cluster->execute_http(
3340
+ req, [barrier](couchbase::operations::bucket_flush_response&& resp) mutable { barrier->set_value(resp); });
2555
3341
  auto resp = f.get();
2556
3342
  if (resp.ec) {
2557
3343
  exc = cb__map_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
@@ -2654,16 +3440,20 @@ cb_Backend_bucket_get_all(VALUE self, VALUE timeout)
2654
3440
 
2655
3441
  if (!backend->cluster) {
2656
3442
  rb_raise(rb_eArgError, "Cluster has been closed already");
3443
+ return Qnil;
2657
3444
  }
2658
3445
 
2659
3446
  VALUE exc = Qnil;
2660
3447
  do {
2661
3448
  couchbase::operations::bucket_get_all_request req{};
2662
- cb__extract_timeout(req, timeout);
3449
+ exc = cb__extract_timeout(req, timeout);
3450
+ if (!NIL_P(exc)) {
3451
+ break;
3452
+ }
2663
3453
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_all_response>>();
2664
3454
  auto f = barrier->get_future();
2665
3455
  backend->cluster->execute_http(
2666
- req, [barrier](couchbase::operations::bucket_get_all_response resp) mutable { barrier->set_value(resp); });
3456
+ req, [barrier](couchbase::operations::bucket_get_all_response&& resp) mutable { barrier->set_value(resp); });
2667
3457
  auto resp = f.get();
2668
3458
  if (resp.ec) {
2669
3459
  exc = cb__map_error_code(resp.ec, "unable to get list of the buckets of the cluster");
@@ -2691,6 +3481,7 @@ cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE timeout)
2691
3481
 
2692
3482
  if (!backend->cluster) {
2693
3483
  rb_raise(rb_eArgError, "Cluster has been closed already");
3484
+ return Qnil;
2694
3485
  }
2695
3486
 
2696
3487
  Check_Type(bucket_name, T_STRING);
@@ -2698,12 +3489,15 @@ cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE timeout)
2698
3489
  VALUE exc = Qnil;
2699
3490
  do {
2700
3491
  couchbase::operations::bucket_get_request req{};
2701
- cb__extract_timeout(req, timeout);
3492
+ exc = cb__extract_timeout(req, timeout);
3493
+ if (!NIL_P(exc)) {
3494
+ break;
3495
+ }
2702
3496
  req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2703
3497
  auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_response>>();
2704
3498
  auto f = barrier->get_future();
2705
3499
  backend->cluster->execute_http(req,
2706
- [barrier](couchbase::operations::bucket_get_response resp) mutable { barrier->set_value(resp); });
3500
+ [barrier](couchbase::operations::bucket_get_response&& resp) mutable { barrier->set_value(resp); });
2707
3501
  auto resp = f.get();
2708
3502
  if (resp.ec) {
2709
3503
  exc = cb__map_error_code(resp.ec, fmt::format("unable to locate bucket \"{}\" on the cluster", req.name));
@@ -2747,16 +3541,20 @@ cb_Backend_role_get_all(VALUE self, VALUE timeout)
2747
3541
 
2748
3542
  if (!backend->cluster) {
2749
3543
  rb_raise(rb_eArgError, "Cluster has been closed already");
3544
+ return Qnil;
2750
3545
  }
2751
3546
 
2752
3547
  VALUE exc = Qnil;
2753
3548
  do {
2754
3549
  couchbase::operations::role_get_all_request req{};
2755
- cb__extract_timeout(req, timeout);
3550
+ exc = cb__extract_timeout(req, timeout);
3551
+ if (!NIL_P(exc)) {
3552
+ break;
3553
+ }
2756
3554
  auto barrier = std::make_shared<std::promise<couchbase::operations::role_get_all_response>>();
2757
3555
  auto f = barrier->get_future();
2758
- backend->cluster->execute_http(req,
2759
- [barrier](couchbase::operations::role_get_all_response resp) mutable { barrier->set_value(resp); });
3556
+ backend->cluster->execute_http(
3557
+ req, [barrier](couchbase::operations::role_get_all_response&& resp) mutable { barrier->set_value(resp); });
2760
3558
  auto resp = f.get();
2761
3559
  if (resp.ec) {
2762
3560
  exc = cb__map_error_code(resp.ec, "unable to fetch users");
@@ -2864,6 +3662,7 @@ cb_Backend_user_get_all(VALUE self, VALUE domain, VALUE timeout)
2864
3662
 
2865
3663
  if (!backend->cluster) {
2866
3664
  rb_raise(rb_eArgError, "Cluster has been closed already");
3665
+ return Qnil;
2867
3666
  }
2868
3667
 
2869
3668
  Check_Type(domain, T_SYMBOL);
@@ -2871,7 +3670,10 @@ cb_Backend_user_get_all(VALUE self, VALUE domain, VALUE timeout)
2871
3670
  VALUE exc = Qnil;
2872
3671
  do {
2873
3672
  couchbase::operations::user_get_all_request req{};
2874
- cb__extract_timeout(req, timeout);
3673
+ exc = cb__extract_timeout(req, timeout);
3674
+ if (!NIL_P(exc)) {
3675
+ break;
3676
+ }
2875
3677
  if (domain == rb_id2sym(rb_intern("local"))) {
2876
3678
  req.domain = couchbase::operations::rbac::auth_domain::local;
2877
3679
  } else if (domain == rb_id2sym(rb_intern("external"))) {
@@ -2882,8 +3684,8 @@ cb_Backend_user_get_all(VALUE self, VALUE domain, VALUE timeout)
2882
3684
  }
2883
3685
  auto barrier = std::make_shared<std::promise<couchbase::operations::user_get_all_response>>();
2884
3686
  auto f = barrier->get_future();
2885
- backend->cluster->execute_http(req,
2886
- [barrier](couchbase::operations::user_get_all_response resp) mutable { barrier->set_value(resp); });
3687
+ backend->cluster->execute_http(
3688
+ req, [barrier](couchbase::operations::user_get_all_response&& resp) mutable { barrier->set_value(resp); });
2887
3689
  auto resp = f.get();
2888
3690
  if (resp.ec) {
2889
3691
  exc = cb__map_error_code(resp.ec, "unable to fetch users");
@@ -2910,6 +3712,7 @@ cb_Backend_user_get(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2910
3712
 
2911
3713
  if (!backend->cluster) {
2912
3714
  rb_raise(rb_eArgError, "Cluster has been closed already");
3715
+ return Qnil;
2913
3716
  }
2914
3717
 
2915
3718
  Check_Type(domain, T_SYMBOL);
@@ -2918,7 +3721,10 @@ cb_Backend_user_get(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2918
3721
  VALUE exc = Qnil;
2919
3722
  do {
2920
3723
  couchbase::operations::user_get_request req{};
2921
- cb__extract_timeout(req, timeout);
3724
+ exc = cb__extract_timeout(req, timeout);
3725
+ if (!NIL_P(exc)) {
3726
+ break;
3727
+ }
2922
3728
  if (domain == rb_id2sym(rb_intern("local"))) {
2923
3729
  req.domain = couchbase::operations::rbac::auth_domain::local;
2924
3730
  } else if (domain == rb_id2sym(rb_intern("external"))) {
@@ -2930,7 +3736,8 @@ cb_Backend_user_get(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2930
3736
  req.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
2931
3737
  auto barrier = std::make_shared<std::promise<couchbase::operations::user_get_response>>();
2932
3738
  auto f = barrier->get_future();
2933
- backend->cluster->execute_http(req, [barrier](couchbase::operations::user_get_response resp) mutable { barrier->set_value(resp); });
3739
+ backend->cluster->execute_http(req,
3740
+ [barrier](couchbase::operations::user_get_response&& resp) mutable { barrier->set_value(resp); });
2934
3741
  auto resp = f.get();
2935
3742
  if (resp.ec) {
2936
3743
  exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to fetch user "{}")", req.username).c_str());
@@ -2953,6 +3760,7 @@ cb_Backend_user_drop(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2953
3760
 
2954
3761
  if (!backend->cluster) {
2955
3762
  rb_raise(rb_eArgError, "Cluster has been closed already");
3763
+ return Qnil;
2956
3764
  }
2957
3765
 
2958
3766
  Check_Type(domain, T_SYMBOL);
@@ -2961,7 +3769,10 @@ cb_Backend_user_drop(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2961
3769
  VALUE exc = Qnil;
2962
3770
  do {
2963
3771
  couchbase::operations::user_drop_request req{};
2964
- cb__extract_timeout(req, timeout);
3772
+ exc = cb__extract_timeout(req, timeout);
3773
+ if (!NIL_P(exc)) {
3774
+ break;
3775
+ }
2965
3776
  if (domain == rb_id2sym(rb_intern("local"))) {
2966
3777
  req.domain = couchbase::operations::rbac::auth_domain::local;
2967
3778
  } else if (domain == rb_id2sym(rb_intern("external"))) {
@@ -2974,7 +3785,7 @@ cb_Backend_user_drop(VALUE self, VALUE domain, VALUE username, VALUE timeout)
2974
3785
  auto barrier = std::make_shared<std::promise<couchbase::operations::user_drop_response>>();
2975
3786
  auto f = barrier->get_future();
2976
3787
  backend->cluster->execute_http(req,
2977
- [barrier](couchbase::operations::user_drop_response resp) mutable { barrier->set_value(resp); });
3788
+ [barrier](couchbase::operations::user_drop_response&& resp) mutable { barrier->set_value(resp); });
2978
3789
  auto resp = f.get();
2979
3790
  if (resp.ec) {
2980
3791
  exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to fetch user "{}")", req.username).c_str());
@@ -2995,6 +3806,7 @@ cb_Backend_user_upsert(VALUE self, VALUE domain, VALUE user, VALUE timeout)
2995
3806
 
2996
3807
  if (!backend->cluster) {
2997
3808
  rb_raise(rb_eArgError, "Cluster has been closed already");
3809
+ return Qnil;
2998
3810
  }
2999
3811
 
3000
3812
  Check_Type(domain, T_SYMBOL);
@@ -3003,7 +3815,10 @@ cb_Backend_user_upsert(VALUE self, VALUE domain, VALUE user, VALUE timeout)
3003
3815
  VALUE exc = Qnil;
3004
3816
  do {
3005
3817
  couchbase::operations::user_upsert_request req{};
3006
- cb__extract_timeout(req, timeout);
3818
+ exc = cb__extract_timeout(req, timeout);
3819
+ if (!NIL_P(exc)) {
3820
+ break;
3821
+ }
3007
3822
  if (domain == rb_id2sym(rb_intern("local"))) {
3008
3823
  req.domain = couchbase::operations::rbac::auth_domain::local;
3009
3824
  } else if (domain == rb_id2sym(rb_intern("external"))) {
@@ -3015,6 +3830,7 @@ cb_Backend_user_upsert(VALUE self, VALUE domain, VALUE user, VALUE timeout)
3015
3830
  VALUE name = rb_hash_aref(user, rb_id2sym(rb_intern("username")));
3016
3831
  if (NIL_P(name) || TYPE(name) != T_STRING) {
3017
3832
  exc = rb_exc_new_cstr(eInvalidArgument, "unable to upsert user: missing name");
3833
+ break;
3018
3834
  }
3019
3835
  req.user.username.assign(RSTRING_PTR(name), static_cast<size_t>(RSTRING_LEN(name)));
3020
3836
  VALUE display_name = rb_hash_aref(user, rb_id2sym(rb_intern("display_name")));
@@ -3065,7 +3881,7 @@ cb_Backend_user_upsert(VALUE self, VALUE domain, VALUE user, VALUE timeout)
3065
3881
  auto barrier = std::make_shared<std::promise<couchbase::operations::user_upsert_response>>();
3066
3882
  auto f = barrier->get_future();
3067
3883
  backend->cluster->execute_http(req,
3068
- [barrier](couchbase::operations::user_upsert_response resp) mutable { barrier->set_value(resp); });
3884
+ [barrier](couchbase::operations::user_upsert_response&& resp) mutable { barrier->set_value(resp); });
3069
3885
  auto resp = f.get();
3070
3886
  if (resp.ec) {
3071
3887
  exc = cb__map_error_code(
@@ -3119,16 +3935,20 @@ cb_Backend_group_get_all(VALUE self, VALUE timeout)
3119
3935
 
3120
3936
  if (!backend->cluster) {
3121
3937
  rb_raise(rb_eArgError, "Cluster has been closed already");
3938
+ return Qnil;
3122
3939
  }
3123
3940
 
3124
3941
  VALUE exc = Qnil;
3125
3942
  do {
3126
3943
  couchbase::operations::group_get_all_request req{};
3127
- cb__extract_timeout(req, timeout);
3944
+ exc = cb__extract_timeout(req, timeout);
3945
+ if (!NIL_P(exc)) {
3946
+ break;
3947
+ }
3128
3948
  auto barrier = std::make_shared<std::promise<couchbase::operations::group_get_all_response>>();
3129
3949
  auto f = barrier->get_future();
3130
- backend->cluster->execute_http(req,
3131
- [barrier](couchbase::operations::group_get_all_response resp) mutable { barrier->set_value(resp); });
3950
+ backend->cluster->execute_http(
3951
+ req, [barrier](couchbase::operations::group_get_all_response&& resp) mutable { barrier->set_value(resp); });
3132
3952
  auto resp = f.get();
3133
3953
  if (resp.ec) {
3134
3954
  exc = cb__map_error_code(resp.ec, "unable to fetch groups");
@@ -3155,6 +3975,7 @@ cb_Backend_group_get(VALUE self, VALUE name, VALUE timeout)
3155
3975
 
3156
3976
  if (!backend->cluster) {
3157
3977
  rb_raise(rb_eArgError, "Cluster has been closed already");
3978
+ return Qnil;
3158
3979
  }
3159
3980
 
3160
3981
  Check_Type(name, T_STRING);
@@ -3162,15 +3983,18 @@ cb_Backend_group_get(VALUE self, VALUE name, VALUE timeout)
3162
3983
  VALUE exc = Qnil;
3163
3984
  do {
3164
3985
  couchbase::operations::group_get_request req{};
3165
- cb__extract_timeout(req, timeout);
3986
+ exc = cb__extract_timeout(req, timeout);
3987
+ if (!NIL_P(exc)) {
3988
+ break;
3989
+ }
3166
3990
  req.name.assign(RSTRING_PTR(name), static_cast<size_t>(RSTRING_LEN(name)));
3167
3991
  auto barrier = std::make_shared<std::promise<couchbase::operations::group_get_response>>();
3168
3992
  auto f = barrier->get_future();
3169
3993
  backend->cluster->execute_http(req,
3170
- [barrier](couchbase::operations::group_get_response resp) mutable { barrier->set_value(resp); });
3994
+ [barrier](couchbase::operations::group_get_response&& resp) mutable { barrier->set_value(resp); });
3171
3995
  auto resp = f.get();
3172
3996
  if (resp.ec) {
3173
- exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to fetch group "{}")", req.name).c_str());
3997
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to fetch group "{}")", req.name));
3174
3998
  break;
3175
3999
  }
3176
4000
 
@@ -3190,6 +4014,7 @@ cb_Backend_group_drop(VALUE self, VALUE name, VALUE timeout)
3190
4014
 
3191
4015
  if (!backend->cluster) {
3192
4016
  rb_raise(rb_eArgError, "Cluster has been closed already");
4017
+ return Qnil;
3193
4018
  }
3194
4019
 
3195
4020
  Check_Type(name, T_STRING);
@@ -3197,15 +4022,18 @@ cb_Backend_group_drop(VALUE self, VALUE name, VALUE timeout)
3197
4022
  VALUE exc = Qnil;
3198
4023
  do {
3199
4024
  couchbase::operations::group_drop_request req{};
3200
- cb__extract_timeout(req, timeout);
4025
+ exc = cb__extract_timeout(req, timeout);
4026
+ if (!NIL_P(exc)) {
4027
+ break;
4028
+ }
3201
4029
  req.name.assign(RSTRING_PTR(name), static_cast<size_t>(RSTRING_LEN(name)));
3202
4030
  auto barrier = std::make_shared<std::promise<couchbase::operations::group_drop_response>>();
3203
4031
  auto f = barrier->get_future();
3204
4032
  backend->cluster->execute_http(req,
3205
- [barrier](couchbase::operations::group_drop_response resp) mutable { barrier->set_value(resp); });
4033
+ [barrier](couchbase::operations::group_drop_response&& resp) mutable { barrier->set_value(resp); });
3206
4034
  auto resp = f.get();
3207
4035
  if (resp.ec) {
3208
- exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to drop group "{}")", req.name).c_str());
4036
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to drop group "{}")", req.name));
3209
4037
  break;
3210
4038
  }
3211
4039
 
@@ -3223,6 +4051,7 @@ cb_Backend_group_upsert(VALUE self, VALUE group, VALUE timeout)
3223
4051
 
3224
4052
  if (!backend->cluster) {
3225
4053
  rb_raise(rb_eArgError, "Cluster has been closed already");
4054
+ return Qnil;
3226
4055
  }
3227
4056
 
3228
4057
  Check_Type(group, T_HASH);
@@ -3230,10 +4059,14 @@ cb_Backend_group_upsert(VALUE self, VALUE group, VALUE timeout)
3230
4059
  VALUE exc = Qnil;
3231
4060
  do {
3232
4061
  couchbase::operations::group_upsert_request req{};
3233
- cb__extract_timeout(req, timeout);
4062
+ exc = cb__extract_timeout(req, timeout);
4063
+ if (!NIL_P(exc)) {
4064
+ break;
4065
+ }
3234
4066
  VALUE name = rb_hash_aref(group, rb_id2sym(rb_intern("name")));
3235
4067
  if (NIL_P(name) || TYPE(name) != T_STRING) {
3236
4068
  exc = rb_exc_new_cstr(eInvalidArgument, "unable to upsert group: missing name");
4069
+ break;
3237
4070
  }
3238
4071
  req.group.name.assign(RSTRING_PTR(name), static_cast<size_t>(RSTRING_LEN(name)));
3239
4072
  VALUE ldap_group_ref = rb_hash_aref(group, rb_id2sym(rb_intern("ldap_group_reference")));
@@ -3272,8 +4105,8 @@ cb_Backend_group_upsert(VALUE self, VALUE group, VALUE timeout)
3272
4105
  }
3273
4106
  auto barrier = std::make_shared<std::promise<couchbase::operations::group_upsert_response>>();
3274
4107
  auto f = barrier->get_future();
3275
- backend->cluster->execute_http(req,
3276
- [barrier](couchbase::operations::group_upsert_response resp) mutable { barrier->set_value(resp); });
4108
+ backend->cluster->execute_http(
4109
+ req, [barrier](couchbase::operations::group_upsert_response&& resp) mutable { barrier->set_value(resp); });
3277
4110
  auto resp = f.get();
3278
4111
  if (resp.ec) {
3279
4112
  exc = cb__map_error_code(
@@ -3295,6 +4128,7 @@ cb_Backend_cluster_enable_developer_preview(VALUE self)
3295
4128
 
3296
4129
  if (!backend->cluster) {
3297
4130
  rb_raise(rb_eArgError, "Cluster has been closed already");
4131
+ return Qnil;
3298
4132
  }
3299
4133
 
3300
4134
  VALUE exc = Qnil;
@@ -3303,7 +4137,7 @@ cb_Backend_cluster_enable_developer_preview(VALUE self)
3303
4137
  auto barrier = std::make_shared<std::promise<couchbase::operations::cluster_developer_preview_enable_response>>();
3304
4138
  auto f = barrier->get_future();
3305
4139
  backend->cluster->execute_http(
3306
- req, [barrier](couchbase::operations::cluster_developer_preview_enable_response resp) mutable { barrier->set_value(resp); });
4140
+ req, [barrier](couchbase::operations::cluster_developer_preview_enable_response&& resp) mutable { barrier->set_value(resp); });
3307
4141
  auto resp = f.get();
3308
4142
  if (resp.ec) {
3309
4143
  exc = cb__map_error_code(resp.ec, fmt::format("unable to enable developer preview for this cluster"));
@@ -3326,6 +4160,7 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
3326
4160
 
3327
4161
  if (!backend->cluster) {
3328
4162
  rb_raise(rb_eArgError, "Cluster has been closed already");
4163
+ return Qnil;
3329
4164
  }
3330
4165
 
3331
4166
  Check_Type(bucket_name, T_STRING);
@@ -3333,12 +4168,15 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
3333
4168
  VALUE exc = Qnil;
3334
4169
  do {
3335
4170
  couchbase::operations::scope_get_all_request req{};
3336
- cb__extract_timeout(req, timeout);
4171
+ exc = cb__extract_timeout(req, timeout);
4172
+ if (!NIL_P(exc)) {
4173
+ break;
4174
+ }
3337
4175
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3338
4176
  auto barrier = std::make_shared<std::promise<couchbase::operations::scope_get_all_response>>();
3339
4177
  auto f = barrier->get_future();
3340
- backend->cluster->execute_http(req,
3341
- [barrier](couchbase::operations::scope_get_all_response resp) mutable { barrier->set_value(resp); });
4178
+ backend->cluster->execute_http(
4179
+ req, [barrier](couchbase::operations::scope_get_all_response&& resp) mutable { barrier->set_value(resp); });
3342
4180
  auto resp = f.get();
3343
4181
  if (resp.ec) {
3344
4182
  exc = cb__map_error_code(resp.ec, fmt::format("unable to get list of the scopes of the bucket \"{}\"", req.bucket_name));
@@ -3378,6 +4216,7 @@ cb_Backend_collections_manifest_get(VALUE self, VALUE bucket_name, VALUE timeout
3378
4216
 
3379
4217
  if (!backend->cluster) {
3380
4218
  rb_raise(rb_eArgError, "Cluster has been closed already");
4219
+ return Qnil;
3381
4220
  }
3382
4221
 
3383
4222
  Check_Type(bucket_name, T_STRING);
@@ -3385,12 +4224,15 @@ cb_Backend_collections_manifest_get(VALUE self, VALUE bucket_name, VALUE timeout
3385
4224
  VALUE exc = Qnil;
3386
4225
  do {
3387
4226
  couchbase::operations::collections_manifest_get_request req{};
3388
- cb__extract_timeout(req, timeout);
4227
+ exc = cb__extract_timeout(req, timeout);
4228
+ if (!NIL_P(exc)) {
4229
+ break;
4230
+ }
3389
4231
  req.id.bucket.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3390
4232
  auto barrier = std::make_shared<std::promise<couchbase::operations::collections_manifest_get_response>>();
3391
4233
  auto f = barrier->get_future();
3392
4234
  backend->cluster->execute(
3393
- req, [barrier](couchbase::operations::collections_manifest_get_response resp) mutable { barrier->set_value(resp); });
4235
+ req, [barrier](couchbase::operations::collections_manifest_get_response&& resp) mutable { barrier->set_value(resp); });
3394
4236
  auto resp = f.get();
3395
4237
  if (resp.ec) {
3396
4238
  exc = cb__map_error_code(resp.ec, fmt::format("unable to get collections manifest of the bucket \"{}\"", req.id.bucket));
@@ -3430,6 +4272,7 @@ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE t
3430
4272
 
3431
4273
  if (!backend->cluster) {
3432
4274
  rb_raise(rb_eArgError, "Cluster has been closed already");
4275
+ return Qnil;
3433
4276
  }
3434
4277
 
3435
4278
  Check_Type(bucket_name, T_STRING);
@@ -3438,13 +4281,16 @@ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE t
3438
4281
  VALUE exc = Qnil;
3439
4282
  do {
3440
4283
  couchbase::operations::scope_create_request req{};
3441
- cb__extract_timeout(req, timeout);
4284
+ exc = cb__extract_timeout(req, timeout);
4285
+ if (!NIL_P(exc)) {
4286
+ break;
4287
+ }
3442
4288
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3443
4289
  req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
3444
4290
  auto barrier = std::make_shared<std::promise<couchbase::operations::scope_create_response>>();
3445
4291
  auto f = barrier->get_future();
3446
- backend->cluster->execute_http(req,
3447
- [barrier](couchbase::operations::scope_create_response resp) mutable { barrier->set_value(resp); });
4292
+ backend->cluster->execute_http(
4293
+ req, [barrier](couchbase::operations::scope_create_response&& resp) mutable { barrier->set_value(resp); });
3448
4294
  auto resp = f.get();
3449
4295
  if (resp.ec) {
3450
4296
  exc = cb__map_error_code(resp.ec,
@@ -3465,6 +4311,7 @@ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE tim
3465
4311
 
3466
4312
  if (!backend->cluster) {
3467
4313
  rb_raise(rb_eArgError, "Cluster has been closed already");
4314
+ return Qnil;
3468
4315
  }
3469
4316
 
3470
4317
  Check_Type(bucket_name, T_STRING);
@@ -3473,13 +4320,16 @@ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE tim
3473
4320
  VALUE exc = Qnil;
3474
4321
  do {
3475
4322
  couchbase::operations::scope_drop_request req{};
3476
- cb__extract_timeout(req, timeout);
4323
+ exc = cb__extract_timeout(req, timeout);
4324
+ if (!NIL_P(exc)) {
4325
+ break;
4326
+ }
3477
4327
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3478
4328
  req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
3479
4329
  auto barrier = std::make_shared<std::promise<couchbase::operations::scope_drop_response>>();
3480
4330
  auto f = barrier->get_future();
3481
4331
  backend->cluster->execute_http(req,
3482
- [barrier](couchbase::operations::scope_drop_response resp) mutable { barrier->set_value(resp); });
4332
+ [barrier](couchbase::operations::scope_drop_response&& resp) mutable { barrier->set_value(resp); });
3483
4333
  auto resp = f.get();
3484
4334
  if (resp.ec) {
3485
4335
  exc = cb__map_error_code(resp.ec,
@@ -3500,6 +4350,7 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
3500
4350
 
3501
4351
  if (!backend->cluster) {
3502
4352
  rb_raise(rb_eArgError, "Cluster has been closed already");
4353
+ return Qnil;
3503
4354
  }
3504
4355
 
3505
4356
  Check_Type(bucket_name, T_STRING);
@@ -3509,7 +4360,10 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
3509
4360
  VALUE exc = Qnil;
3510
4361
  do {
3511
4362
  couchbase::operations::collection_create_request req{};
3512
- cb__extract_timeout(req, timeout);
4363
+ exc = cb__extract_timeout(req, timeout);
4364
+ if (!NIL_P(exc)) {
4365
+ break;
4366
+ }
3513
4367
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3514
4368
  req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
3515
4369
  req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
@@ -3521,7 +4375,7 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
3521
4375
  auto barrier = std::make_shared<std::promise<couchbase::operations::collection_create_response>>();
3522
4376
  auto f = barrier->get_future();
3523
4377
  backend->cluster->execute_http(
3524
- req, [barrier](couchbase::operations::collection_create_response resp) mutable { barrier->set_value(resp); });
4378
+ req, [barrier](couchbase::operations::collection_create_response&& resp) mutable { barrier->set_value(resp); });
3525
4379
  auto resp = f.get();
3526
4380
  if (resp.ec) {
3527
4381
  exc = cb__map_error_code(
@@ -3544,6 +4398,7 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
3544
4398
 
3545
4399
  if (!backend->cluster) {
3546
4400
  rb_raise(rb_eArgError, "Cluster has been closed already");
4401
+ return Qnil;
3547
4402
  }
3548
4403
 
3549
4404
  Check_Type(bucket_name, T_STRING);
@@ -3553,7 +4408,10 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
3553
4408
  VALUE exc = Qnil;
3554
4409
  do {
3555
4410
  couchbase::operations::collection_drop_request req{};
3556
- cb__extract_timeout(req, timeout);
4411
+ exc = cb__extract_timeout(req, timeout);
4412
+ if (!NIL_P(exc)) {
4413
+ break;
4414
+ }
3557
4415
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3558
4416
  req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
3559
4417
  req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
@@ -3561,7 +4419,7 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
3561
4419
  auto barrier = std::make_shared<std::promise<couchbase::operations::collection_drop_response>>();
3562
4420
  auto f = barrier->get_future();
3563
4421
  backend->cluster->execute_http(
3564
- req, [barrier](couchbase::operations::collection_drop_response resp) mutable { barrier->set_value(resp); });
4422
+ req, [barrier](couchbase::operations::collection_drop_response&& resp) mutable { barrier->set_value(resp); });
3565
4423
  auto resp = f.get();
3566
4424
  if (resp.ec) {
3567
4425
  exc = cb__map_error_code(
@@ -3584,6 +4442,7 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
3584
4442
 
3585
4443
  if (!backend->cluster) {
3586
4444
  rb_raise(rb_eArgError, "Cluster has been closed already");
4445
+ return Qnil;
3587
4446
  }
3588
4447
 
3589
4448
  Check_Type(bucket_name, T_STRING);
@@ -3591,12 +4450,15 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
3591
4450
  VALUE exc = Qnil;
3592
4451
  do {
3593
4452
  couchbase::operations::query_index_get_all_request req{};
3594
- cb__extract_timeout(req, timeout);
4453
+ exc = cb__extract_timeout(req, timeout);
4454
+ if (!NIL_P(exc)) {
4455
+ break;
4456
+ }
3595
4457
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3596
4458
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_get_all_response>>();
3597
4459
  auto f = barrier->get_future();
3598
4460
  backend->cluster->execute_http(
3599
- req, [barrier](couchbase::operations::query_index_get_all_response resp) mutable { barrier->set_value(resp); });
4461
+ req, [barrier](couchbase::operations::query_index_get_all_response&& resp) mutable { barrier->set_value(resp); });
3600
4462
  auto resp = f.get();
3601
4463
  if (resp.ec) {
3602
4464
  exc = cb__map_error_code(resp.ec, fmt::format("unable to get list of the indexes of the bucket \"{}\"", req.bucket_name));
@@ -3655,6 +4517,7 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
3655
4517
 
3656
4518
  if (!backend->cluster) {
3657
4519
  rb_raise(rb_eArgError, "Cluster has been closed already");
4520
+ return Qnil;
3658
4521
  }
3659
4522
 
3660
4523
  Check_Type(bucket_name, T_STRING);
@@ -3664,7 +4527,10 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
3664
4527
  VALUE exc = Qnil;
3665
4528
  do {
3666
4529
  couchbase::operations::query_index_create_request req{};
3667
- cb__extract_timeout(req, timeout);
4530
+ exc = cb__extract_timeout(req, timeout);
4531
+ if (!NIL_P(exc)) {
4532
+ break;
4533
+ }
3668
4534
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3669
4535
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3670
4536
  auto fields_num = static_cast<size_t>(RARRAY_LEN(fields));
@@ -3709,7 +4575,7 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
3709
4575
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
3710
4576
  auto f = barrier->get_future();
3711
4577
  backend->cluster->execute_http(
3712
- req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
4578
+ req, [barrier](couchbase::operations::query_index_create_response&& resp) mutable { barrier->set_value(resp); });
3713
4579
  auto resp = f.get();
3714
4580
  if (resp.ec) {
3715
4581
  if (!resp.errors.empty()) {
@@ -3752,6 +4618,7 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
3752
4618
 
3753
4619
  if (!backend->cluster) {
3754
4620
  rb_raise(rb_eArgError, "Cluster has been closed already");
4621
+ return Qnil;
3755
4622
  }
3756
4623
 
3757
4624
  Check_Type(bucket_name, T_STRING);
@@ -3760,7 +4627,10 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
3760
4627
  VALUE exc = Qnil;
3761
4628
  do {
3762
4629
  couchbase::operations::query_index_drop_request req{};
3763
- cb__extract_timeout(req, timeout);
4630
+ exc = cb__extract_timeout(req, timeout);
4631
+ if (!NIL_P(exc)) {
4632
+ break;
4633
+ }
3764
4634
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3765
4635
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3766
4636
  if (!NIL_P(options)) {
@@ -3784,7 +4654,7 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
3784
4654
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
3785
4655
  auto f = barrier->get_future();
3786
4656
  backend->cluster->execute_http(
3787
- req, [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
4657
+ req, [barrier](couchbase::operations::query_index_drop_response&& resp) mutable { barrier->set_value(resp); });
3788
4658
  auto resp = f.get();
3789
4659
  if (resp.ec) {
3790
4660
  if (!resp.errors.empty()) {
@@ -3827,6 +4697,7 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
3827
4697
 
3828
4698
  if (!backend->cluster) {
3829
4699
  rb_raise(rb_eArgError, "Cluster has been closed already");
4700
+ return Qnil;
3830
4701
  }
3831
4702
 
3832
4703
  Check_Type(bucket_name, T_STRING);
@@ -3837,7 +4708,10 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
3837
4708
  VALUE exc = Qnil;
3838
4709
  do {
3839
4710
  couchbase::operations::query_index_create_request req{};
3840
- cb__extract_timeout(req, timeout);
4711
+ exc = cb__extract_timeout(req, timeout);
4712
+ if (!NIL_P(exc)) {
4713
+ break;
4714
+ }
3841
4715
  req.is_primary = true;
3842
4716
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3843
4717
  if (!NIL_P(options)) {
@@ -3875,7 +4749,7 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
3875
4749
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
3876
4750
  auto f = barrier->get_future();
3877
4751
  backend->cluster->execute_http(
3878
- req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
4752
+ req, [barrier](couchbase::operations::query_index_create_response&& resp) mutable { barrier->set_value(resp); });
3879
4753
  auto resp = f.get();
3880
4754
  if (resp.ec) {
3881
4755
  if (!resp.errors.empty()) {
@@ -3917,6 +4791,7 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
3917
4791
 
3918
4792
  if (!backend->cluster) {
3919
4793
  rb_raise(rb_eArgError, "Cluster has been closed already");
4794
+ return Qnil;
3920
4795
  }
3921
4796
 
3922
4797
  Check_Type(bucket_name, T_STRING);
@@ -3924,7 +4799,10 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
3924
4799
  VALUE exc = Qnil;
3925
4800
  do {
3926
4801
  couchbase::operations::query_index_drop_request req{};
3927
- cb__extract_timeout(req, timeout);
4802
+ exc = cb__extract_timeout(req, timeout);
4803
+ if (!NIL_P(exc)) {
4804
+ break;
4805
+ }
3928
4806
  req.is_primary = true;
3929
4807
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
3930
4808
  if (!NIL_P(options)) {
@@ -3954,7 +4832,7 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
3954
4832
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
3955
4833
  auto f = barrier->get_future();
3956
4834
  backend->cluster->execute_http(
3957
- req, [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
4835
+ req, [barrier](couchbase::operations::query_index_drop_response&& resp) mutable { barrier->set_value(resp); });
3958
4836
  auto resp = f.get();
3959
4837
  if (resp.ec) {
3960
4838
  if (!resp.errors.empty()) {
@@ -3994,6 +4872,7 @@ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE timeo
3994
4872
 
3995
4873
  if (!backend->cluster) {
3996
4874
  rb_raise(rb_eArgError, "Cluster has been closed already");
4875
+ return Qnil;
3997
4876
  }
3998
4877
 
3999
4878
  Check_Type(bucket_name, T_STRING);
@@ -4001,12 +4880,15 @@ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE timeo
4001
4880
  VALUE exc = Qnil;
4002
4881
  do {
4003
4882
  couchbase::operations::query_index_build_deferred_request req{};
4004
- cb__extract_timeout(req, timeout);
4883
+ exc = cb__extract_timeout(req, timeout);
4884
+ if (!NIL_P(exc)) {
4885
+ break;
4886
+ }
4005
4887
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
4006
4888
  auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_build_deferred_response>>();
4007
4889
  auto f = barrier->get_future();
4008
4890
  backend->cluster->execute_http(
4009
- req, [barrier](couchbase::operations::query_index_build_deferred_response resp) mutable { barrier->set_value(resp); });
4891
+ req, [barrier](couchbase::operations::query_index_build_deferred_response&& resp) mutable { barrier->set_value(resp); });
4010
4892
  auto resp = f.get();
4011
4893
  if (resp.ec) {
4012
4894
  if (!resp.errors.empty()) {
@@ -4036,6 +4918,7 @@ cb_Backend_query_index_watch(VALUE self, VALUE bucket_name, VALUE index_names, V
4036
4918
 
4037
4919
  if (!backend->cluster) {
4038
4920
  rb_raise(rb_eArgError, "Cluster has been closed already");
4921
+ return Qnil;
4039
4922
  }
4040
4923
 
4041
4924
  Check_Type(bucket_name, T_STRING);
@@ -4087,16 +4970,20 @@ cb_Backend_search_index_get_all(VALUE self, VALUE timeout)
4087
4970
 
4088
4971
  if (!backend->cluster) {
4089
4972
  rb_raise(rb_eArgError, "Cluster has been closed already");
4973
+ return Qnil;
4090
4974
  }
4091
4975
 
4092
4976
  VALUE exc = Qnil;
4093
4977
  do {
4094
4978
  couchbase::operations::search_index_get_all_request req{};
4095
- cb__extract_timeout(req, timeout);
4979
+ exc = cb__extract_timeout(req, timeout);
4980
+ if (!NIL_P(exc)) {
4981
+ break;
4982
+ }
4096
4983
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_all_response>>();
4097
4984
  auto f = barrier->get_future();
4098
4985
  backend->cluster->execute_http(
4099
- req, [barrier](couchbase::operations::search_index_get_all_response resp) mutable { barrier->set_value(resp); });
4986
+ req, [barrier](couchbase::operations::search_index_get_all_response&& resp) mutable { barrier->set_value(resp); });
4100
4987
  auto resp = f.get();
4101
4988
  if (resp.ec) {
4102
4989
  exc = cb__map_error_code(resp.ec, "unable to get list of the search indexes");
@@ -4127,18 +5014,22 @@ cb_Backend_search_index_get(VALUE self, VALUE index_name, VALUE timeout)
4127
5014
 
4128
5015
  if (!backend->cluster) {
4129
5016
  rb_raise(rb_eArgError, "Cluster has been closed already");
5017
+ return Qnil;
4130
5018
  }
4131
5019
 
4132
5020
  Check_Type(index_name, T_STRING);
4133
5021
  VALUE exc = Qnil;
4134
5022
  do {
4135
5023
  couchbase::operations::search_index_get_request req{};
4136
- cb__extract_timeout(req, timeout);
5024
+ exc = cb__extract_timeout(req, timeout);
5025
+ if (!NIL_P(exc)) {
5026
+ break;
5027
+ }
4137
5028
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4138
5029
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_response>>();
4139
5030
  auto f = barrier->get_future();
4140
5031
  backend->cluster->execute_http(
4141
- req, [barrier](couchbase::operations::search_index_get_response resp) mutable { barrier->set_value(resp); });
5032
+ req, [barrier](couchbase::operations::search_index_get_response&& resp) mutable { barrier->set_value(resp); });
4142
5033
  auto resp = f.get();
4143
5034
  if (resp.ec) {
4144
5035
  if (resp.error.empty()) {
@@ -4164,13 +5055,17 @@ cb_Backend_search_index_upsert(VALUE self, VALUE index_definition, VALUE timeout
4164
5055
 
4165
5056
  if (!backend->cluster) {
4166
5057
  rb_raise(rb_eArgError, "Cluster has been closed already");
5058
+ return Qnil;
4167
5059
  }
4168
5060
 
4169
5061
  Check_Type(index_definition, T_HASH);
4170
5062
  VALUE exc = Qnil;
4171
5063
  do {
4172
5064
  couchbase::operations::search_index_upsert_request req{};
4173
- cb__extract_timeout(req, timeout);
5065
+ exc = cb__extract_timeout(req, timeout);
5066
+ if (!NIL_P(exc)) {
5067
+ break;
5068
+ }
4174
5069
 
4175
5070
  VALUE index_name = rb_hash_aref(index_definition, rb_id2sym(rb_intern("name")));
4176
5071
  Check_Type(index_name, T_STRING);
@@ -4223,7 +5118,7 @@ cb_Backend_search_index_upsert(VALUE self, VALUE index_definition, VALUE timeout
4223
5118
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_upsert_response>>();
4224
5119
  auto f = barrier->get_future();
4225
5120
  backend->cluster->execute_http(
4226
- req, [barrier](couchbase::operations::search_index_upsert_response resp) mutable { barrier->set_value(resp); });
5121
+ req, [barrier](couchbase::operations::search_index_upsert_response&& resp) mutable { barrier->set_value(resp); });
4227
5122
  auto resp = f.get();
4228
5123
  if (resp.ec) {
4229
5124
  if (resp.error.empty()) {
@@ -4249,18 +5144,22 @@ cb_Backend_search_index_drop(VALUE self, VALUE index_name, VALUE timeout)
4249
5144
 
4250
5145
  if (!backend->cluster) {
4251
5146
  rb_raise(rb_eArgError, "Cluster has been closed already");
5147
+ return Qnil;
4252
5148
  }
4253
5149
 
4254
5150
  Check_Type(index_name, T_STRING);
4255
5151
  VALUE exc = Qnil;
4256
5152
  do {
4257
5153
  couchbase::operations::search_index_drop_request req{};
4258
- cb__extract_timeout(req, timeout);
5154
+ exc = cb__extract_timeout(req, timeout);
5155
+ if (!NIL_P(exc)) {
5156
+ break;
5157
+ }
4259
5158
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4260
5159
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_drop_response>>();
4261
5160
  auto f = barrier->get_future();
4262
5161
  backend->cluster->execute_http(
4263
- req, [barrier](couchbase::operations::search_index_drop_response resp) mutable { barrier->set_value(resp); });
5162
+ req, [barrier](couchbase::operations::search_index_drop_response&& resp) mutable { barrier->set_value(resp); });
4264
5163
  auto resp = f.get();
4265
5164
  if (resp.ec) {
4266
5165
  if (resp.error.empty()) {
@@ -4286,18 +5185,22 @@ cb_Backend_search_index_get_documents_count(VALUE self, VALUE index_name, VALUE
4286
5185
 
4287
5186
  if (!backend->cluster) {
4288
5187
  rb_raise(rb_eArgError, "Cluster has been closed already");
5188
+ return Qnil;
4289
5189
  }
4290
5190
 
4291
5191
  Check_Type(index_name, T_STRING);
4292
5192
  VALUE exc = Qnil;
4293
5193
  do {
4294
5194
  couchbase::operations::search_index_get_documents_count_request req{};
4295
- cb__extract_timeout(req, timeout);
5195
+ exc = cb__extract_timeout(req, timeout);
5196
+ if (!NIL_P(exc)) {
5197
+ break;
5198
+ }
4296
5199
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4297
5200
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_documents_count_response>>();
4298
5201
  auto f = barrier->get_future();
4299
5202
  backend->cluster->execute_http(
4300
- req, [barrier](couchbase::operations::search_index_get_documents_count_response resp) mutable { barrier->set_value(resp); });
5203
+ req, [barrier](couchbase::operations::search_index_get_documents_count_response&& resp) mutable { barrier->set_value(resp); });
4301
5204
  auto resp = f.get();
4302
5205
  if (resp.ec) {
4303
5206
  if (resp.error.empty()) {
@@ -4327,18 +5230,22 @@ cb_Backend_search_index_get_stats(VALUE self, VALUE index_name, VALUE timeout)
4327
5230
 
4328
5231
  if (!backend->cluster) {
4329
5232
  rb_raise(rb_eArgError, "Cluster has been closed already");
5233
+ return Qnil;
4330
5234
  }
4331
5235
 
4332
5236
  Check_Type(index_name, T_STRING);
4333
5237
  VALUE exc = Qnil;
4334
5238
  do {
4335
5239
  couchbase::operations::search_index_get_stats_request req{};
4336
- cb__extract_timeout(req, timeout);
5240
+ exc = cb__extract_timeout(req, timeout);
5241
+ if (!NIL_P(exc)) {
5242
+ break;
5243
+ }
4337
5244
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4338
5245
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_stats_response>>();
4339
5246
  auto f = barrier->get_future();
4340
5247
  backend->cluster->execute_http(
4341
- req, [barrier](couchbase::operations::search_index_get_stats_response resp) mutable { barrier->set_value(resp); });
5248
+ req, [barrier](couchbase::operations::search_index_get_stats_response&& resp) mutable { barrier->set_value(resp); });
4342
5249
  auto resp = f.get();
4343
5250
  if (resp.ec) {
4344
5251
  if (resp.error.empty()) {
@@ -4363,16 +5270,20 @@ cb_Backend_search_get_stats(VALUE self, VALUE timeout)
4363
5270
 
4364
5271
  if (!backend->cluster) {
4365
5272
  rb_raise(rb_eArgError, "Cluster has been closed already");
5273
+ return Qnil;
4366
5274
  }
4367
5275
 
4368
5276
  VALUE exc = Qnil;
4369
5277
  do {
4370
5278
  couchbase::operations::search_index_stats_request req{};
4371
- cb__extract_timeout(req, timeout);
5279
+ exc = cb__extract_timeout(req, timeout);
5280
+ if (!NIL_P(exc)) {
5281
+ break;
5282
+ }
4372
5283
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_stats_response>>();
4373
5284
  auto f = barrier->get_future();
4374
5285
  backend->cluster->execute_http(
4375
- req, [barrier](couchbase::operations::search_index_stats_response resp) mutable { barrier->set_value(resp); });
5286
+ req, [barrier](couchbase::operations::search_index_stats_response&& resp) mutable { barrier->set_value(resp); });
4376
5287
  auto resp = f.get();
4377
5288
  if (resp.ec) {
4378
5289
  exc = cb__map_error_code(resp.ec, "unable to get stats for the search service");
@@ -4392,19 +5303,23 @@ cb_Backend_search_index_pause_ingest(VALUE self, VALUE index_name, VALUE timeout
4392
5303
 
4393
5304
  if (!backend->cluster) {
4394
5305
  rb_raise(rb_eArgError, "Cluster has been closed already");
5306
+ return Qnil;
4395
5307
  }
4396
5308
 
4397
5309
  Check_Type(index_name, T_STRING);
4398
5310
  VALUE exc = Qnil;
4399
5311
  do {
4400
5312
  couchbase::operations::search_index_control_ingest_request req{};
4401
- cb__extract_timeout(req, timeout);
5313
+ exc = cb__extract_timeout(req, timeout);
5314
+ if (!NIL_P(exc)) {
5315
+ break;
5316
+ }
4402
5317
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4403
5318
  req.pause = true;
4404
5319
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_ingest_response>>();
4405
5320
  auto f = barrier->get_future();
4406
5321
  backend->cluster->execute_http(
4407
- req, [barrier](couchbase::operations::search_index_control_ingest_response resp) mutable { barrier->set_value(resp); });
5322
+ req, [barrier](couchbase::operations::search_index_control_ingest_response&& resp) mutable { barrier->set_value(resp); });
4408
5323
  auto resp = f.get();
4409
5324
  if (resp.ec) {
4410
5325
  if (resp.error.empty()) {
@@ -4431,19 +5346,23 @@ cb_Backend_search_index_resume_ingest(VALUE self, VALUE index_name, VALUE timeou
4431
5346
 
4432
5347
  if (!backend->cluster) {
4433
5348
  rb_raise(rb_eArgError, "Cluster has been closed already");
5349
+ return Qnil;
4434
5350
  }
4435
5351
 
4436
5352
  Check_Type(index_name, T_STRING);
4437
5353
  VALUE exc = Qnil;
4438
5354
  do {
4439
5355
  couchbase::operations::search_index_control_ingest_request req{};
4440
- cb__extract_timeout(req, timeout);
5356
+ exc = cb__extract_timeout(req, timeout);
5357
+ if (!NIL_P(exc)) {
5358
+ break;
5359
+ }
4441
5360
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4442
5361
  req.pause = false;
4443
5362
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_ingest_response>>();
4444
5363
  auto f = barrier->get_future();
4445
5364
  backend->cluster->execute_http(
4446
- req, [barrier](couchbase::operations::search_index_control_ingest_response resp) mutable { barrier->set_value(resp); });
5365
+ req, [barrier](couchbase::operations::search_index_control_ingest_response&& resp) mutable { barrier->set_value(resp); });
4447
5366
  auto resp = f.get();
4448
5367
  if (resp.ec) {
4449
5368
  if (resp.error.empty()) {
@@ -4470,19 +5389,23 @@ cb_Backend_search_index_allow_querying(VALUE self, VALUE index_name, VALUE timeo
4470
5389
 
4471
5390
  if (!backend->cluster) {
4472
5391
  rb_raise(rb_eArgError, "Cluster has been closed already");
5392
+ return Qnil;
4473
5393
  }
4474
5394
 
4475
5395
  Check_Type(index_name, T_STRING);
4476
5396
  VALUE exc = Qnil;
4477
5397
  do {
4478
5398
  couchbase::operations::search_index_control_query_request req{};
4479
- cb__extract_timeout(req, timeout);
5399
+ exc = cb__extract_timeout(req, timeout);
5400
+ if (!NIL_P(exc)) {
5401
+ break;
5402
+ }
4480
5403
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4481
5404
  req.allow = true;
4482
5405
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_query_response>>();
4483
5406
  auto f = barrier->get_future();
4484
5407
  backend->cluster->execute_http(
4485
- req, [barrier](couchbase::operations::search_index_control_query_response resp) mutable { barrier->set_value(resp); });
5408
+ req, [barrier](couchbase::operations::search_index_control_query_response&& resp) mutable { barrier->set_value(resp); });
4486
5409
  auto resp = f.get();
4487
5410
  if (resp.ec) {
4488
5411
  if (resp.error.empty()) {
@@ -4509,19 +5432,23 @@ cb_Backend_search_index_disallow_querying(VALUE self, VALUE index_name, VALUE ti
4509
5432
 
4510
5433
  if (!backend->cluster) {
4511
5434
  rb_raise(rb_eArgError, "Cluster has been closed already");
5435
+ return Qnil;
4512
5436
  }
4513
5437
 
4514
5438
  Check_Type(index_name, T_STRING);
4515
5439
  VALUE exc = Qnil;
4516
5440
  do {
4517
5441
  couchbase::operations::search_index_control_query_request req{};
4518
- cb__extract_timeout(req, timeout);
5442
+ exc = cb__extract_timeout(req, timeout);
5443
+ if (!NIL_P(exc)) {
5444
+ break;
5445
+ }
4519
5446
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4520
5447
  req.allow = false;
4521
5448
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_query_response>>();
4522
5449
  auto f = barrier->get_future();
4523
5450
  backend->cluster->execute_http(
4524
- req, [barrier](couchbase::operations::search_index_control_query_response resp) mutable { barrier->set_value(resp); });
5451
+ req, [barrier](couchbase::operations::search_index_control_query_response&& resp) mutable { barrier->set_value(resp); });
4525
5452
  auto resp = f.get();
4526
5453
  if (resp.ec) {
4527
5454
  if (resp.error.empty()) {
@@ -4548,19 +5475,23 @@ cb_Backend_search_index_freeze_plan(VALUE self, VALUE index_name, VALUE timeout)
4548
5475
 
4549
5476
  if (!backend->cluster) {
4550
5477
  rb_raise(rb_eArgError, "Cluster has been closed already");
5478
+ return Qnil;
4551
5479
  }
4552
5480
 
4553
5481
  Check_Type(index_name, T_STRING);
4554
5482
  VALUE exc = Qnil;
4555
5483
  do {
4556
5484
  couchbase::operations::search_index_control_plan_freeze_request req{};
4557
- cb__extract_timeout(req, timeout);
5485
+ exc = cb__extract_timeout(req, timeout);
5486
+ if (!NIL_P(exc)) {
5487
+ break;
5488
+ }
4558
5489
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4559
5490
  req.freeze = true;
4560
5491
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_plan_freeze_response>>();
4561
5492
  auto f = barrier->get_future();
4562
5493
  backend->cluster->execute_http(
4563
- req, [barrier](couchbase::operations::search_index_control_plan_freeze_response resp) mutable { barrier->set_value(resp); });
5494
+ req, [barrier](couchbase::operations::search_index_control_plan_freeze_response&& resp) mutable { barrier->set_value(resp); });
4564
5495
  auto resp = f.get();
4565
5496
  if (resp.ec) {
4566
5497
  if (resp.error.empty()) {
@@ -4587,19 +5518,23 @@ cb_Backend_search_index_unfreeze_plan(VALUE self, VALUE index_name, VALUE timeou
4587
5518
 
4588
5519
  if (!backend->cluster) {
4589
5520
  rb_raise(rb_eArgError, "Cluster has been closed already");
5521
+ return Qnil;
4590
5522
  }
4591
5523
 
4592
5524
  Check_Type(index_name, T_STRING);
4593
5525
  VALUE exc = Qnil;
4594
5526
  do {
4595
5527
  couchbase::operations::search_index_control_plan_freeze_request req{};
4596
- cb__extract_timeout(req, timeout);
5528
+ exc = cb__extract_timeout(req, timeout);
5529
+ if (!NIL_P(exc)) {
5530
+ break;
5531
+ }
4597
5532
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4598
5533
  req.freeze = false;
4599
5534
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_plan_freeze_response>>();
4600
5535
  auto f = barrier->get_future();
4601
5536
  backend->cluster->execute_http(
4602
- req, [barrier](couchbase::operations::search_index_control_plan_freeze_response resp) mutable { barrier->set_value(resp); });
5537
+ req, [barrier](couchbase::operations::search_index_control_plan_freeze_response&& resp) mutable { barrier->set_value(resp); });
4603
5538
  auto resp = f.get();
4604
5539
  if (resp.ec) {
4605
5540
  if (resp.error.empty()) {
@@ -4626,6 +5561,7 @@ cb_Backend_search_index_analyze_document(VALUE self, VALUE index_name, VALUE enc
4626
5561
 
4627
5562
  if (!backend->cluster) {
4628
5563
  rb_raise(rb_eArgError, "Cluster has been closed already");
5564
+ return Qnil;
4629
5565
  }
4630
5566
 
4631
5567
  Check_Type(index_name, T_STRING);
@@ -4633,7 +5569,10 @@ cb_Backend_search_index_analyze_document(VALUE self, VALUE index_name, VALUE enc
4633
5569
  VALUE exc = Qnil;
4634
5570
  do {
4635
5571
  couchbase::operations::search_index_analyze_document_request req{};
4636
- cb__extract_timeout(req, timeout);
5572
+ exc = cb__extract_timeout(req, timeout);
5573
+ if (!NIL_P(exc)) {
5574
+ break;
5575
+ }
4637
5576
 
4638
5577
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4639
5578
  req.encoded_document.assign(RSTRING_PTR(encoded_document), static_cast<size_t>(RSTRING_LEN(encoded_document)));
@@ -4641,7 +5580,7 @@ cb_Backend_search_index_analyze_document(VALUE self, VALUE index_name, VALUE enc
4641
5580
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_analyze_document_response>>();
4642
5581
  auto f = barrier->get_future();
4643
5582
  backend->cluster->execute_http(
4644
- req, [barrier](couchbase::operations::search_index_analyze_document_response resp) mutable { barrier->set_value(resp); });
5583
+ req, [barrier](couchbase::operations::search_index_analyze_document_response&& resp) mutable { barrier->set_value(resp); });
4645
5584
  auto resp = f.get();
4646
5585
  if (resp.ec) {
4647
5586
  if (resp.error.empty()) {
@@ -4669,6 +5608,7 @@ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE opti
4669
5608
 
4670
5609
  if (!backend->cluster) {
4671
5610
  rb_raise(rb_eArgError, "Cluster has been closed already");
5611
+ return Qnil;
4672
5612
  }
4673
5613
 
4674
5614
  Check_Type(index_name, T_STRING);
@@ -4683,7 +5623,10 @@ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE opti
4683
5623
  Check_Type(client_context_id, T_STRING);
4684
5624
  req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
4685
5625
  }
4686
- cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
5626
+ exc = cb__extract_timeout(req, options);
5627
+ if (!NIL_P(exc)) {
5628
+ break;
5629
+ }
4687
5630
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
4688
5631
  req.query = tao::json::from_string(std::string(RSTRING_PTR(query), static_cast<size_t>(RSTRING_LEN(query))));
4689
5632
 
@@ -4823,7 +5766,7 @@ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE opti
4823
5766
 
4824
5767
  auto barrier = std::make_shared<std::promise<couchbase::operations::search_response>>();
4825
5768
  auto f = barrier->get_future();
4826
- backend->cluster->execute_http(req, [barrier](couchbase::operations::search_response resp) mutable { barrier->set_value(resp); });
5769
+ backend->cluster->execute_http(req, [barrier](couchbase::operations::search_response&& resp) mutable { barrier->set_value(resp); });
4827
5770
  auto resp = f.get();
4828
5771
  if (resp.ec) {
4829
5772
  exc =
@@ -4994,6 +5937,7 @@ cb_Backend_dns_srv(VALUE self, VALUE hostname, VALUE service)
4994
5937
  tls = true;
4995
5938
  } else {
4996
5939
  rb_raise(rb_eArgError, "Unsupported service type: %+" PRIsVALUE, service);
5940
+ return Qnil;
4997
5941
  }
4998
5942
  VALUE exc = Qnil;
4999
5943
  do {
@@ -5007,8 +5951,9 @@ cb_Backend_dns_srv(VALUE self, VALUE hostname, VALUE service)
5007
5951
  }
5008
5952
  auto barrier = std::make_shared<std::promise<couchbase::io::dns::dns_client::dns_srv_response>>();
5009
5953
  auto f = barrier->get_future();
5010
- client.query_srv(
5011
- host_name, service_name, [barrier](couchbase::io::dns::dns_client::dns_srv_response resp) mutable { barrier->set_value(resp); });
5954
+ client.query_srv(host_name, service_name, [barrier](couchbase::io::dns::dns_client::dns_srv_response&& resp) mutable {
5955
+ barrier->set_value(resp);
5956
+ });
5012
5957
  ctx.run();
5013
5958
  auto resp = f.get();
5014
5959
  if (resp.ec) {
@@ -5038,16 +5983,20 @@ cb_Backend_analytics_get_pending_mutations(VALUE self, VALUE timeout)
5038
5983
 
5039
5984
  if (!backend->cluster) {
5040
5985
  rb_raise(rb_eArgError, "Cluster has been closed already");
5986
+ return Qnil;
5041
5987
  }
5042
5988
 
5043
5989
  VALUE exc = Qnil;
5044
5990
  do {
5045
5991
  couchbase::operations::analytics_get_pending_mutations_request req{};
5046
- cb__extract_timeout(req, timeout);
5992
+ exc = cb__extract_timeout(req, timeout);
5993
+ if (!NIL_P(exc)) {
5994
+ break;
5995
+ }
5047
5996
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_get_pending_mutations_response>>();
5048
5997
  auto f = barrier->get_future();
5049
5998
  backend->cluster->execute_http(
5050
- req, [barrier](couchbase::operations::analytics_get_pending_mutations_response resp) mutable { barrier->set_value(resp); });
5999
+ req, [barrier](couchbase::operations::analytics_get_pending_mutations_response&& resp) mutable { barrier->set_value(resp); });
5051
6000
  auto resp = f.get();
5052
6001
  if (resp.ec) {
5053
6002
  if (resp.errors.empty()) {
@@ -5078,16 +6027,20 @@ cb_Backend_analytics_dataset_get_all(VALUE self, VALUE timeout)
5078
6027
 
5079
6028
  if (!backend->cluster) {
5080
6029
  rb_raise(rb_eArgError, "Cluster has been closed already");
6030
+ return Qnil;
5081
6031
  }
5082
6032
 
5083
6033
  VALUE exc = Qnil;
5084
6034
  do {
5085
6035
  couchbase::operations::analytics_dataset_get_all_request req{};
5086
- cb__extract_timeout(req, timeout);
6036
+ exc = cb__extract_timeout(req, timeout);
6037
+ if (!NIL_P(exc)) {
6038
+ break;
6039
+ }
5087
6040
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataset_get_all_response>>();
5088
6041
  auto f = barrier->get_future();
5089
6042
  backend->cluster->execute_http(
5090
- req, [barrier](couchbase::operations::analytics_dataset_get_all_response resp) mutable { barrier->set_value(resp); });
6043
+ req, [barrier](couchbase::operations::analytics_dataset_get_all_response&& resp) mutable { barrier->set_value(resp); });
5091
6044
  auto resp = f.get();
5092
6045
  if (resp.ec) {
5093
6046
  if (resp.errors.empty()) {
@@ -5126,6 +6079,7 @@ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE datavers
5126
6079
 
5127
6080
  if (!backend->cluster) {
5128
6081
  rb_raise(rb_eArgError, "Cluster has been closed already");
6082
+ return Qnil;
5129
6083
  }
5130
6084
 
5131
6085
  Check_Type(dataset_name, T_STRING);
@@ -5136,7 +6090,10 @@ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE datavers
5136
6090
  VALUE exc = Qnil;
5137
6091
  do {
5138
6092
  couchbase::operations::analytics_dataset_drop_request req{};
5139
- cb__extract_timeout(req, timeout);
6093
+ exc = cb__extract_timeout(req, timeout);
6094
+ if (!NIL_P(exc)) {
6095
+ break;
6096
+ }
5140
6097
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
5141
6098
  if (!NIL_P(dataverse_name)) {
5142
6099
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
@@ -5147,7 +6104,7 @@ cb_Backend_analytics_dataset_drop(VALUE self, VALUE dataset_name, VALUE datavers
5147
6104
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataset_drop_response>>();
5148
6105
  auto f = barrier->get_future();
5149
6106
  backend->cluster->execute_http(
5150
- req, [barrier](couchbase::operations::analytics_dataset_drop_response resp) mutable { barrier->set_value(resp); });
6107
+ req, [barrier](couchbase::operations::analytics_dataset_drop_response&& resp) mutable { barrier->set_value(resp); });
5151
6108
  auto resp = f.get();
5152
6109
  if (resp.ec) {
5153
6110
  if (resp.errors.empty()) {
@@ -5183,6 +6140,7 @@ cb_Backend_analytics_dataset_create(VALUE self,
5183
6140
 
5184
6141
  if (!backend->cluster) {
5185
6142
  rb_raise(rb_eArgError, "Cluster has been closed already");
6143
+ return Qnil;
5186
6144
  }
5187
6145
 
5188
6146
  Check_Type(dataset_name, T_STRING);
@@ -5197,7 +6155,10 @@ cb_Backend_analytics_dataset_create(VALUE self,
5197
6155
  VALUE exc = Qnil;
5198
6156
  do {
5199
6157
  couchbase::operations::analytics_dataset_create_request req{};
5200
- cb__extract_timeout(req, timeout);
6158
+ exc = cb__extract_timeout(req, timeout);
6159
+ if (!NIL_P(exc)) {
6160
+ break;
6161
+ }
5201
6162
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
5202
6163
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
5203
6164
  if (!NIL_P(condition)) {
@@ -5212,7 +6173,7 @@ cb_Backend_analytics_dataset_create(VALUE self,
5212
6173
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataset_create_response>>();
5213
6174
  auto f = barrier->get_future();
5214
6175
  backend->cluster->execute_http(
5215
- req, [barrier](couchbase::operations::analytics_dataset_create_response resp) mutable { barrier->set_value(resp); });
6176
+ req, [barrier](couchbase::operations::analytics_dataset_create_response&& resp) mutable { barrier->set_value(resp); });
5216
6177
  auto resp = f.get();
5217
6178
  if (resp.ec) {
5218
6179
  if (resp.errors.empty()) {
@@ -5242,6 +6203,7 @@ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE igno
5242
6203
 
5243
6204
  if (!backend->cluster) {
5244
6205
  rb_raise(rb_eArgError, "Cluster has been closed already");
6206
+ return Qnil;
5245
6207
  }
5246
6208
 
5247
6209
  Check_Type(dataverse_name, T_STRING);
@@ -5249,7 +6211,10 @@ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE igno
5249
6211
  VALUE exc = Qnil;
5250
6212
  do {
5251
6213
  couchbase::operations::analytics_dataverse_drop_request req{};
5252
- cb__extract_timeout(req, timeout);
6214
+ exc = cb__extract_timeout(req, timeout);
6215
+ if (!NIL_P(exc)) {
6216
+ break;
6217
+ }
5253
6218
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
5254
6219
  if (!NIL_P(ignore_if_does_not_exist)) {
5255
6220
  req.ignore_if_does_not_exist = RTEST(ignore_if_does_not_exist);
@@ -5257,7 +6222,7 @@ cb_Backend_analytics_dataverse_drop(VALUE self, VALUE dataverse_name, VALUE igno
5257
6222
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataverse_drop_response>>();
5258
6223
  auto f = barrier->get_future();
5259
6224
  backend->cluster->execute_http(
5260
- req, [barrier](couchbase::operations::analytics_dataverse_drop_response resp) mutable { barrier->set_value(resp); });
6225
+ req, [barrier](couchbase::operations::analytics_dataverse_drop_response&& resp) mutable { barrier->set_value(resp); });
5261
6226
  auto resp = f.get();
5262
6227
  if (resp.ec) {
5263
6228
  if (resp.errors.empty()) {
@@ -5284,6 +6249,7 @@ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ig
5284
6249
 
5285
6250
  if (!backend->cluster) {
5286
6251
  rb_raise(rb_eArgError, "Cluster has been closed already");
6252
+ return Qnil;
5287
6253
  }
5288
6254
 
5289
6255
  Check_Type(dataverse_name, T_STRING);
@@ -5294,7 +6260,10 @@ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ig
5294
6260
  VALUE exc = Qnil;
5295
6261
  do {
5296
6262
  couchbase::operations::analytics_dataverse_create_request req{};
5297
- cb__extract_timeout(req, timeout);
6263
+ exc = cb__extract_timeout(req, timeout);
6264
+ if (!NIL_P(exc)) {
6265
+ break;
6266
+ }
5298
6267
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
5299
6268
  if (!NIL_P(ignore_if_exists)) {
5300
6269
  req.ignore_if_exists = RTEST(ignore_if_exists);
@@ -5302,7 +6271,7 @@ cb_Backend_analytics_dataverse_create(VALUE self, VALUE dataverse_name, VALUE ig
5302
6271
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_dataverse_create_response>>();
5303
6272
  auto f = barrier->get_future();
5304
6273
  backend->cluster->execute_http(
5305
- req, [barrier](couchbase::operations::analytics_dataverse_create_response resp) mutable { barrier->set_value(resp); });
6274
+ req, [barrier](couchbase::operations::analytics_dataverse_create_response&& resp) mutable { barrier->set_value(resp); });
5306
6275
  auto resp = f.get();
5307
6276
  if (resp.ec) {
5308
6277
  if (resp.errors.empty()) {
@@ -5329,16 +6298,20 @@ cb_Backend_analytics_index_get_all(VALUE self, VALUE timeout)
5329
6298
 
5330
6299
  if (!backend->cluster) {
5331
6300
  rb_raise(rb_eArgError, "Cluster has been closed already");
6301
+ return Qnil;
5332
6302
  }
5333
6303
 
5334
6304
  VALUE exc = Qnil;
5335
6305
  do {
5336
6306
  couchbase::operations::analytics_index_get_all_request req{};
5337
- cb__extract_timeout(req, timeout);
6307
+ exc = cb__extract_timeout(req, timeout);
6308
+ if (!NIL_P(exc)) {
6309
+ break;
6310
+ }
5338
6311
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_index_get_all_response>>();
5339
6312
  auto f = barrier->get_future();
5340
6313
  backend->cluster->execute_http(
5341
- req, [barrier](couchbase::operations::analytics_index_get_all_response resp) mutable { barrier->set_value(resp); });
6314
+ req, [barrier](couchbase::operations::analytics_index_get_all_response&& resp) mutable { barrier->set_value(resp); });
5342
6315
  auto resp = f.get();
5343
6316
  if (resp.ec) {
5344
6317
  if (resp.errors.empty()) {
@@ -5382,6 +6355,7 @@ cb_Backend_analytics_index_create(VALUE self,
5382
6355
 
5383
6356
  if (!backend->cluster) {
5384
6357
  rb_raise(rb_eArgError, "Cluster has been closed already");
6358
+ return Qnil;
5385
6359
  }
5386
6360
 
5387
6361
  Check_Type(index_name, T_STRING);
@@ -5394,7 +6368,10 @@ cb_Backend_analytics_index_create(VALUE self,
5394
6368
  VALUE exc = Qnil;
5395
6369
  do {
5396
6370
  couchbase::operations::analytics_index_create_request req{};
5397
- cb__extract_timeout(req, timeout);
6371
+ exc = cb__extract_timeout(req, timeout);
6372
+ if (!NIL_P(exc)) {
6373
+ break;
6374
+ }
5398
6375
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
5399
6376
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
5400
6377
  auto fields_num = static_cast<size_t>(RARRAY_LEN(fields));
@@ -5417,7 +6394,7 @@ cb_Backend_analytics_index_create(VALUE self,
5417
6394
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_index_create_response>>();
5418
6395
  auto f = barrier->get_future();
5419
6396
  backend->cluster->execute_http(
5420
- req, [barrier](couchbase::operations::analytics_index_create_response resp) mutable { barrier->set_value(resp); });
6397
+ req, [barrier](couchbase::operations::analytics_index_create_response&& resp) mutable { barrier->set_value(resp); });
5421
6398
  auto resp = f.get();
5422
6399
  if (resp.ec) {
5423
6400
  if (resp.errors.empty()) {
@@ -5454,6 +6431,7 @@ cb_Backend_analytics_index_drop(VALUE self,
5454
6431
 
5455
6432
  if (!backend->cluster) {
5456
6433
  rb_raise(rb_eArgError, "Cluster has been closed already");
6434
+ return Qnil;
5457
6435
  }
5458
6436
 
5459
6437
  Check_Type(index_name, T_STRING);
@@ -5465,7 +6443,10 @@ cb_Backend_analytics_index_drop(VALUE self,
5465
6443
  VALUE exc = Qnil;
5466
6444
  do {
5467
6445
  couchbase::operations::analytics_index_drop_request req{};
5468
- cb__extract_timeout(req, timeout);
6446
+ exc = cb__extract_timeout(req, timeout);
6447
+ if (!NIL_P(exc)) {
6448
+ break;
6449
+ }
5469
6450
  req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
5470
6451
  req.dataset_name.assign(RSTRING_PTR(dataset_name), static_cast<size_t>(RSTRING_LEN(dataset_name)));
5471
6452
  if (!NIL_P(dataverse_name)) {
@@ -5477,7 +6458,7 @@ cb_Backend_analytics_index_drop(VALUE self,
5477
6458
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_index_drop_response>>();
5478
6459
  auto f = barrier->get_future();
5479
6460
  backend->cluster->execute_http(
5480
- req, [barrier](couchbase::operations::analytics_index_drop_response resp) mutable { barrier->set_value(resp); });
6461
+ req, [barrier](couchbase::operations::analytics_index_drop_response&& resp) mutable { barrier->set_value(resp); });
5481
6462
  auto resp = f.get();
5482
6463
  if (resp.ec) {
5483
6464
  if (resp.errors.empty()) {
@@ -5509,6 +6490,7 @@ cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALU
5509
6490
 
5510
6491
  if (!backend->cluster) {
5511
6492
  rb_raise(rb_eArgError, "Cluster has been closed already");
6493
+ return Qnil;
5512
6494
  }
5513
6495
 
5514
6496
  Check_Type(link_name, T_STRING);
@@ -5519,7 +6501,10 @@ cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALU
5519
6501
  VALUE exc = Qnil;
5520
6502
  do {
5521
6503
  couchbase::operations::analytics_link_connect_request req{};
5522
- cb__extract_timeout(req, timeout);
6504
+ exc = cb__extract_timeout(req, timeout);
6505
+ if (!NIL_P(exc)) {
6506
+ break;
6507
+ }
5523
6508
  req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
5524
6509
  if (!NIL_P(dataverse_name)) {
5525
6510
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
@@ -5530,7 +6515,7 @@ cb_Backend_analytics_link_connect(VALUE self, VALUE link_name, VALUE force, VALU
5530
6515
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_connect_response>>();
5531
6516
  auto f = barrier->get_future();
5532
6517
  backend->cluster->execute_http(
5533
- req, [barrier](couchbase::operations::analytics_link_connect_response resp) mutable { barrier->set_value(resp); });
6518
+ req, [barrier](couchbase::operations::analytics_link_connect_response&& resp) mutable { barrier->set_value(resp); });
5534
6519
  auto resp = f.get();
5535
6520
  if (resp.ec) {
5536
6521
  if (resp.errors.empty()) {
@@ -5560,6 +6545,7 @@ cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE datavers
5560
6545
 
5561
6546
  if (!backend->cluster) {
5562
6547
  rb_raise(rb_eArgError, "Cluster has been closed already");
6548
+ return Qnil;
5563
6549
  }
5564
6550
 
5565
6551
  Check_Type(link_name, T_STRING);
@@ -5570,7 +6556,10 @@ cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE datavers
5570
6556
  VALUE exc = Qnil;
5571
6557
  do {
5572
6558
  couchbase::operations::analytics_link_disconnect_request req{};
5573
- cb__extract_timeout(req, timeout);
6559
+ exc = cb__extract_timeout(req, timeout);
6560
+ if (!NIL_P(exc)) {
6561
+ break;
6562
+ }
5574
6563
  req.link_name.assign(RSTRING_PTR(link_name), static_cast<size_t>(RSTRING_LEN(link_name)));
5575
6564
  if (!NIL_P(dataverse_name)) {
5576
6565
  req.dataverse_name.assign(RSTRING_PTR(dataverse_name), static_cast<size_t>(RSTRING_LEN(dataverse_name)));
@@ -5578,7 +6567,7 @@ cb_Backend_analytics_link_disconnect(VALUE self, VALUE link_name, VALUE datavers
5578
6567
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_link_disconnect_response>>();
5579
6568
  auto f = barrier->get_future();
5580
6569
  backend->cluster->execute_http(
5581
- req, [barrier](couchbase::operations::analytics_link_disconnect_response resp) mutable { barrier->set_value(resp); });
6570
+ req, [barrier](couchbase::operations::analytics_link_disconnect_response&& resp) mutable { barrier->set_value(resp); });
5582
6571
  auto resp = f.get();
5583
6572
  if (resp.ec) {
5584
6573
  if (resp.errors.empty()) {
@@ -5620,6 +6609,7 @@ cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
5620
6609
 
5621
6610
  if (!backend->cluster) {
5622
6611
  rb_raise(rb_eArgError, "Cluster has been closed already");
6612
+ return Qnil;
5623
6613
  }
5624
6614
 
5625
6615
  Check_Type(statement, T_STRING);
@@ -5634,7 +6624,10 @@ cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
5634
6624
  Check_Type(client_context_id, T_STRING);
5635
6625
  req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
5636
6626
  }
5637
- cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
6627
+ exc = cb__extract_timeout(req, options);
6628
+ if (!NIL_P(exc)) {
6629
+ break;
6630
+ }
5638
6631
  VALUE readonly = rb_hash_aref(options, rb_id2sym(rb_intern("readonly")));
5639
6632
  if (!NIL_P(readonly)) {
5640
6633
  req.readonly = RTEST(readonly);
@@ -5680,7 +6673,7 @@ cb_Backend_document_analytics(VALUE self, VALUE statement, VALUE options)
5680
6673
  auto barrier = std::make_shared<std::promise<couchbase::operations::analytics_response>>();
5681
6674
  auto f = barrier->get_future();
5682
6675
  backend->cluster->execute_http(req,
5683
- [barrier](couchbase::operations::analytics_response resp) mutable { barrier->set_value(resp); });
6676
+ [barrier](couchbase::operations::analytics_response&& resp) mutable { barrier->set_value(resp); });
5684
6677
  auto resp = f.get();
5685
6678
  if (resp.ec) {
5686
6679
  if (resp.payload.meta_data.errors && !resp.payload.meta_data.errors->empty()) {
@@ -5845,6 +6838,7 @@ cb_Backend_view_index_get_all(VALUE self, VALUE bucket_name, VALUE name_space, V
5845
6838
 
5846
6839
  if (!backend->cluster) {
5847
6840
  rb_raise(rb_eArgError, "Cluster has been closed already");
6841
+ return Qnil;
5848
6842
  }
5849
6843
 
5850
6844
  Check_Type(bucket_name, T_STRING);
@@ -5858,6 +6852,7 @@ cb_Backend_view_index_get_all(VALUE self, VALUE bucket_name, VALUE name_space, V
5858
6852
  ns = couchbase::operations::design_document::name_space::production;
5859
6853
  } else {
5860
6854
  rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
6855
+ return Qnil;
5861
6856
  }
5862
6857
 
5863
6858
  VALUE exc = Qnil;
@@ -5865,11 +6860,14 @@ cb_Backend_view_index_get_all(VALUE self, VALUE bucket_name, VALUE name_space, V
5865
6860
  couchbase::operations::view_index_get_all_request req{};
5866
6861
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
5867
6862
  req.name_space = ns;
5868
- cb__extract_timeout(req, timeout);
6863
+ exc = cb__extract_timeout(req, timeout);
6864
+ if (!NIL_P(exc)) {
6865
+ break;
6866
+ }
5869
6867
  auto barrier = std::make_shared<std::promise<couchbase::operations::view_index_get_all_response>>();
5870
6868
  auto f = barrier->get_future();
5871
6869
  backend->cluster->execute_http(
5872
- req, [barrier](couchbase::operations::view_index_get_all_response resp) mutable { barrier->set_value(resp); });
6870
+ req, [barrier](couchbase::operations::view_index_get_all_response&& resp) mutable { barrier->set_value(resp); });
5873
6871
  auto resp = f.get();
5874
6872
  if (resp.ec) {
5875
6873
  exc = cb__map_error_code(resp.ec, "unable to get list of the design documents");
@@ -5922,6 +6920,7 @@ cb_Backend_view_index_get(VALUE self, VALUE bucket_name, VALUE document_name, VA
5922
6920
 
5923
6921
  if (!backend->cluster) {
5924
6922
  rb_raise(rb_eArgError, "Cluster has been closed already");
6923
+ return Qnil;
5925
6924
  }
5926
6925
 
5927
6926
  Check_Type(bucket_name, T_STRING);
@@ -5936,6 +6935,7 @@ cb_Backend_view_index_get(VALUE self, VALUE bucket_name, VALUE document_name, VA
5936
6935
  ns = couchbase::operations::design_document::name_space::production;
5937
6936
  } else {
5938
6937
  rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
6938
+ return Qnil;
5939
6939
  }
5940
6940
 
5941
6941
  VALUE exc = Qnil;
@@ -5944,11 +6944,14 @@ cb_Backend_view_index_get(VALUE self, VALUE bucket_name, VALUE document_name, VA
5944
6944
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
5945
6945
  req.document_name.assign(RSTRING_PTR(document_name), static_cast<size_t>(RSTRING_LEN(document_name)));
5946
6946
  req.name_space = ns;
5947
- cb__extract_timeout(req, timeout);
6947
+ exc = cb__extract_timeout(req, timeout);
6948
+ if (!NIL_P(exc)) {
6949
+ break;
6950
+ }
5948
6951
  auto barrier = std::make_shared<std::promise<couchbase::operations::view_index_get_response>>();
5949
6952
  auto f = barrier->get_future();
5950
6953
  backend->cluster->execute_http(
5951
- req, [barrier](couchbase::operations::view_index_get_response resp) mutable { barrier->set_value(resp); });
6954
+ req, [barrier](couchbase::operations::view_index_get_response&& resp) mutable { barrier->set_value(resp); });
5952
6955
  auto resp = f.get();
5953
6956
  if (resp.ec) {
5954
6957
  exc = cb__map_error_code(
@@ -6000,6 +7003,7 @@ cb_Backend_view_index_drop(VALUE self, VALUE bucket_name, VALUE document_name, V
6000
7003
 
6001
7004
  if (!backend->cluster) {
6002
7005
  rb_raise(rb_eArgError, "Cluster has been closed already");
7006
+ return Qnil;
6003
7007
  }
6004
7008
 
6005
7009
  Check_Type(bucket_name, T_STRING);
@@ -6014,6 +7018,7 @@ cb_Backend_view_index_drop(VALUE self, VALUE bucket_name, VALUE document_name, V
6014
7018
  ns = couchbase::operations::design_document::name_space::production;
6015
7019
  } else {
6016
7020
  rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
7021
+ return Qnil;
6017
7022
  }
6018
7023
 
6019
7024
  VALUE exc = Qnil;
@@ -6022,11 +7027,14 @@ cb_Backend_view_index_drop(VALUE self, VALUE bucket_name, VALUE document_name, V
6022
7027
  req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
6023
7028
  req.document_name.assign(RSTRING_PTR(document_name), static_cast<size_t>(RSTRING_LEN(document_name)));
6024
7029
  req.name_space = ns;
6025
- cb__extract_timeout(req, timeout);
7030
+ exc = cb__extract_timeout(req, timeout);
7031
+ if (!NIL_P(exc)) {
7032
+ break;
7033
+ }
6026
7034
  auto barrier = std::make_shared<std::promise<couchbase::operations::view_index_drop_response>>();
6027
7035
  auto f = barrier->get_future();
6028
7036
  backend->cluster->execute_http(
6029
- req, [barrier](couchbase::operations::view_index_drop_response resp) mutable { barrier->set_value(resp); });
7037
+ req, [barrier](couchbase::operations::view_index_drop_response&& resp) mutable { barrier->set_value(resp); });
6030
7038
  auto resp = f.get();
6031
7039
  if (resp.ec) {
6032
7040
  exc = cb__map_error_code(
@@ -6049,6 +7057,7 @@ cb_Backend_view_index_upsert(VALUE self, VALUE bucket_name, VALUE document, VALU
6049
7057
 
6050
7058
  if (!backend->cluster) {
6051
7059
  rb_raise(rb_eArgError, "Cluster has been closed already");
7060
+ return Qnil;
6052
7061
  }
6053
7062
 
6054
7063
  Check_Type(bucket_name, T_STRING);
@@ -6063,6 +7072,7 @@ cb_Backend_view_index_upsert(VALUE self, VALUE bucket_name, VALUE document, VALU
6063
7072
  ns = couchbase::operations::design_document::name_space::production;
6064
7073
  } else {
6065
7074
  rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
7075
+ return Qnil;
6066
7076
  }
6067
7077
 
6068
7078
  VALUE exc = Qnil;
@@ -6098,11 +7108,14 @@ cb_Backend_view_index_upsert(VALUE self, VALUE bucket_name, VALUE document, VALU
6098
7108
  }
6099
7109
  }
6100
7110
 
6101
- cb__extract_timeout(req, timeout);
7111
+ exc = cb__extract_timeout(req, timeout);
7112
+ if (!NIL_P(exc)) {
7113
+ break;
7114
+ }
6102
7115
  auto barrier = std::make_shared<std::promise<couchbase::operations::view_index_upsert_response>>();
6103
7116
  auto f = barrier->get_future();
6104
7117
  backend->cluster->execute_http(
6105
- req, [barrier](couchbase::operations::view_index_upsert_response resp) mutable { barrier->set_value(resp); });
7118
+ req, [barrier](couchbase::operations::view_index_upsert_response&& resp) mutable { barrier->set_value(resp); });
6106
7119
  auto resp = f.get();
6107
7120
  if (resp.ec) {
6108
7121
  exc = cb__map_error_code(
@@ -6125,6 +7138,7 @@ cb_Backend_document_view(VALUE self, VALUE bucket_name, VALUE design_document_na
6125
7138
 
6126
7139
  if (!backend->cluster) {
6127
7140
  rb_raise(rb_eArgError, "Cluster has been closed already");
7141
+ return Qnil;
6128
7142
  }
6129
7143
 
6130
7144
  Check_Type(bucket_name, T_STRING);
@@ -6139,6 +7153,7 @@ cb_Backend_document_view(VALUE self, VALUE bucket_name, VALUE design_document_na
6139
7153
  ns = couchbase::operations::design_document::name_space::production;
6140
7154
  } else {
6141
7155
  rb_raise(rb_eArgError, "Unknown design document namespace: %+" PRIsVALUE, type);
7156
+ return Qnil;
6142
7157
  }
6143
7158
  if (!NIL_P(options)) {
6144
7159
  Check_Type(options, T_HASH);
@@ -6151,8 +7166,11 @@ cb_Backend_document_view(VALUE self, VALUE bucket_name, VALUE design_document_na
6151
7166
  req.document_name.assign(RSTRING_PTR(design_document_name), static_cast<size_t>(RSTRING_LEN(design_document_name)));
6152
7167
  req.view_name.assign(RSTRING_PTR(view_name), static_cast<size_t>(RSTRING_LEN(view_name)));
6153
7168
  req.name_space = ns;
7169
+ exc = cb__extract_timeout(req, options);
7170
+ if (!NIL_P(exc)) {
7171
+ break;
7172
+ }
6154
7173
  if (!NIL_P(options)) {
6155
- cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
6156
7174
  VALUE debug = rb_hash_aref(options, rb_id2sym(rb_intern("debug")));
6157
7175
  if (!NIL_P(debug)) {
6158
7176
  req.debug = RTEST(debug);
@@ -6246,8 +7264,8 @@ cb_Backend_document_view(VALUE self, VALUE bucket_name, VALUE design_document_na
6246
7264
 
6247
7265
  auto barrier = std::make_shared<std::promise<couchbase::operations::document_view_response>>();
6248
7266
  auto f = barrier->get_future();
6249
- backend->cluster->execute_http(req,
6250
- [barrier](couchbase::operations::document_view_response resp) mutable { barrier->set_value(resp); });
7267
+ backend->cluster->execute_http(
7268
+ req, [barrier](couchbase::operations::document_view_response&& resp) mutable { barrier->set_value(resp); });
6251
7269
  auto resp = f.get();
6252
7270
  if (resp.ec) {
6253
7271
  if (resp.error) {
@@ -6301,6 +7319,116 @@ cb_Backend_document_view(VALUE self, VALUE bucket_name, VALUE design_document_na
6301
7319
  return Qnil;
6302
7320
  }
6303
7321
 
7322
+ static VALUE
7323
+ cb_Backend_set_log_level(VALUE self, VALUE log_level)
7324
+ {
7325
+ (void)self;
7326
+ Check_Type(log_level, T_SYMBOL);
7327
+ ID type = rb_sym2id(log_level);
7328
+ if (type == rb_intern("trace")) {
7329
+ spdlog::set_level(spdlog::level::trace);
7330
+ } else if (type == rb_intern("debug")) {
7331
+ spdlog::set_level(spdlog::level::debug);
7332
+ } else if (type == rb_intern("info")) {
7333
+ spdlog::set_level(spdlog::level::info);
7334
+ } else if (type == rb_intern("warn")) {
7335
+ spdlog::set_level(spdlog::level::warn);
7336
+ } else if (type == rb_intern("error")) {
7337
+ spdlog::set_level(spdlog::level::err);
7338
+ } else if (type == rb_intern("critical")) {
7339
+ spdlog::set_level(spdlog::level::critical);
7340
+ } else if (type == rb_intern("off")) {
7341
+ spdlog::set_level(spdlog::level::off);
7342
+ } else {
7343
+ rb_raise(rb_eArgError, "Unsupported log level type: %+" PRIsVALUE, log_level);
7344
+ return Qnil;
7345
+ }
7346
+ return Qnil;
7347
+ }
7348
+
7349
+ static VALUE
7350
+ cb_Backend_get_log_level(VALUE self)
7351
+ {
7352
+ (void)self;
7353
+ switch (spdlog::get_level()) {
7354
+ case spdlog::level::trace:
7355
+ return rb_id2sym(rb_intern("trace"));
7356
+ case spdlog::level::debug:
7357
+ return rb_id2sym(rb_intern("debug"));
7358
+ case spdlog::level::info:
7359
+ return rb_id2sym(rb_intern("info"));
7360
+ case spdlog::level::warn:
7361
+ return rb_id2sym(rb_intern("warn"));
7362
+ case spdlog::level::err:
7363
+ return rb_id2sym(rb_intern("error"));
7364
+ case spdlog::level::critical:
7365
+ return rb_id2sym(rb_intern("critical"));
7366
+ case spdlog::level::off:
7367
+ return rb_id2sym(rb_intern("off"));
7368
+ case spdlog::level::n_levels:
7369
+ return Qnil;
7370
+ }
7371
+ return Qnil;
7372
+ }
7373
+
7374
+ static VALUE
7375
+ cb_Backend_snappy_compress(VALUE self, VALUE data)
7376
+ {
7377
+ (void)self;
7378
+ Check_Type(data, T_STRING);
7379
+
7380
+ std::string compressed{};
7381
+ std::size_t compressed_size = snappy::Compress(RSTRING_PTR(data), static_cast<std::size_t>(RSTRING_LEN(data)), &compressed);
7382
+ return rb_str_new(compressed.data(), static_cast<long>(compressed_size));
7383
+ }
7384
+
7385
+ static VALUE
7386
+ cb_Backend_snappy_uncompress(VALUE self, VALUE data)
7387
+ {
7388
+ (void)self;
7389
+ Check_Type(data, T_STRING);
7390
+
7391
+ std::string uncompressed{};
7392
+ bool success = snappy::Uncompress(RSTRING_PTR(data), static_cast<std::size_t>(RSTRING_LEN(data)), &uncompressed);
7393
+ if (success) {
7394
+ return rb_str_new(uncompressed.data(), static_cast<long>(uncompressed.size()));
7395
+ }
7396
+ rb_raise(rb_eArgError, "Unable to decompress buffer");
7397
+ return Qnil;
7398
+ }
7399
+
7400
+ static VALUE
7401
+ cb_Backend_leb128_encode(VALUE self, VALUE number)
7402
+ {
7403
+ (void)self;
7404
+ switch (TYPE(number)) {
7405
+ case T_FIXNUM:
7406
+ case T_BIGNUM:
7407
+ break;
7408
+ default:
7409
+ rb_raise(rb_eArgError, "The value must be a number");
7410
+ }
7411
+ couchbase::protocol::unsigned_leb128<std::uint64_t> encoded(NUM2ULL(number));
7412
+ std::string buf = encoded.get();
7413
+ return rb_str_new(buf.data(), static_cast<long>(buf.size()));
7414
+ }
7415
+
7416
+ static VALUE
7417
+ cb_Backend_leb128_decode(VALUE self, VALUE data)
7418
+ {
7419
+ (void)self;
7420
+ Check_Type(data, T_STRING);
7421
+ std::string buf(RSTRING_PTR(data), static_cast<std::size_t>(RSTRING_LEN(data)));
7422
+ if (!buf.empty()) {
7423
+ auto rv = couchbase::protocol::decode_unsigned_leb128<std::uint64_t>(buf, couchbase::protocol::Leb128NoThrow());
7424
+ if (rv.second.data()) {
7425
+ return ULL2NUM(rv.first);
7426
+ }
7427
+ }
7428
+ rb_raise(rb_eArgError, "Unable to decode the buffer");
7429
+ return Qnil;
7430
+ }
7431
+
6304
7432
  static void
6305
7433
  init_backend(VALUE mCouchbase)
6306
7434
  {
@@ -6310,23 +7438,29 @@ init_backend(VALUE mCouchbase)
6310
7438
  rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
6311
7439
  rb_define_method(cBackend, "open_bucket", VALUE_FUNC(cb_Backend_open_bucket), 2);
6312
7440
  rb_define_method(cBackend, "diagnostics", VALUE_FUNC(cb_Backend_diagnostics), 1);
7441
+ rb_define_method(cBackend, "ping", VALUE_FUNC(cb_Backend_ping), 2);
6313
7442
 
6314
7443
  rb_define_method(cBackend, "document_get", VALUE_FUNC(cb_Backend_document_get), 4);
6315
- rb_define_method(cBackend, "document_get_projected", VALUE_FUNC(cb_Backend_document_get_projected), 7);
7444
+ rb_define_method(cBackend, "document_get_multi", VALUE_FUNC(cb_Backend_document_get_multi), 2);
7445
+ rb_define_method(cBackend, "document_get_projected", VALUE_FUNC(cb_Backend_document_get_projected), 4);
6316
7446
  rb_define_method(cBackend, "document_get_and_lock", VALUE_FUNC(cb_Backend_document_get_and_lock), 5);
6317
7447
  rb_define_method(cBackend, "document_get_and_touch", VALUE_FUNC(cb_Backend_document_get_and_touch), 5);
6318
- rb_define_method(cBackend, "document_insert", VALUE_FUNC(cb_Backend_document_insert), 7);
6319
- rb_define_method(cBackend, "document_replace", VALUE_FUNC(cb_Backend_document_replace), 7);
6320
- rb_define_method(cBackend, "document_upsert", VALUE_FUNC(cb_Backend_document_upsert), 7);
6321
- rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 5);
6322
- rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 6);
6323
- rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 6);
7448
+ rb_define_method(cBackend, "document_insert", VALUE_FUNC(cb_Backend_document_insert), 6);
7449
+ rb_define_method(cBackend, "document_replace", VALUE_FUNC(cb_Backend_document_replace), 6);
7450
+ rb_define_method(cBackend, "document_upsert", VALUE_FUNC(cb_Backend_document_upsert), 6);
7451
+ rb_define_method(cBackend, "document_upsert_multi", VALUE_FUNC(cb_Backend_document_upsert_multi), 2);
7452
+ rb_define_method(cBackend, "document_append", VALUE_FUNC(cb_Backend_document_append), 5);
7453
+ rb_define_method(cBackend, "document_prepend", VALUE_FUNC(cb_Backend_document_prepend), 5);
7454
+ rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 4);
7455
+ rb_define_method(cBackend, "document_remove_multi", VALUE_FUNC(cb_Backend_document_remove_multi), 2);
7456
+ rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 5);
7457
+ rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 5);
6324
7458
  rb_define_method(cBackend, "document_query", VALUE_FUNC(cb_Backend_document_query), 2);
6325
7459
  rb_define_method(cBackend, "document_touch", VALUE_FUNC(cb_Backend_document_touch), 5);
6326
7460
  rb_define_method(cBackend, "document_exists", VALUE_FUNC(cb_Backend_document_exists), 4);
6327
7461
  rb_define_method(cBackend, "document_unlock", VALUE_FUNC(cb_Backend_document_unlock), 5);
6328
- rb_define_method(cBackend, "document_increment", VALUE_FUNC(cb_Backend_document_increment), 5);
6329
- rb_define_method(cBackend, "document_decrement", VALUE_FUNC(cb_Backend_document_decrement), 5);
7462
+ rb_define_method(cBackend, "document_increment", VALUE_FUNC(cb_Backend_document_increment), 4);
7463
+ rb_define_method(cBackend, "document_decrement", VALUE_FUNC(cb_Backend_document_decrement), 4);
6330
7464
  rb_define_method(cBackend, "document_search", VALUE_FUNC(cb_Backend_document_search), 3);
6331
7465
  rb_define_method(cBackend, "document_analytics", VALUE_FUNC(cb_Backend_document_analytics), 2);
6332
7466
  rb_define_method(cBackend, "document_view", VALUE_FUNC(cb_Backend_document_view), 5);
@@ -6400,6 +7534,12 @@ init_backend(VALUE mCouchbase)
6400
7534
  rb_define_method(cBackend, "collections_manifest_get", VALUE_FUNC(cb_Backend_collections_manifest_get), 2);
6401
7535
  rb_define_singleton_method(cBackend, "dns_srv", VALUE_FUNC(cb_Backend_dns_srv), 2);
6402
7536
  rb_define_singleton_method(cBackend, "parse_connection_string", VALUE_FUNC(cb_Backend_parse_connection_string), 1);
7537
+ rb_define_singleton_method(cBackend, "set_log_level", VALUE_FUNC(cb_Backend_set_log_level), 1);
7538
+ rb_define_singleton_method(cBackend, "get_log_level", VALUE_FUNC(cb_Backend_get_log_level), 0);
7539
+ rb_define_singleton_method(cBackend, "snappy_compress", VALUE_FUNC(cb_Backend_snappy_compress), 1);
7540
+ rb_define_singleton_method(cBackend, "snappy_uncompress", VALUE_FUNC(cb_Backend_snappy_uncompress), 1);
7541
+ rb_define_singleton_method(cBackend, "leb128_encode", VALUE_FUNC(cb_Backend_leb128_encode), 1);
7542
+ rb_define_singleton_method(cBackend, "leb128_decode", VALUE_FUNC(cb_Backend_leb128_decode), 1);
6403
7543
  }
6404
7544
 
6405
7545
  void