couchbase 3.0.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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