couchbase 3.0.0.alpha.2-universal-darwin-19 → 3.0.0.alpha.3-universal-darwin-19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-dev-preview.yml +52 -0
  3. data/.gitmodules +3 -0
  4. data/.idea/vcs.xml +1 -0
  5. data/.yardopts +1 -0
  6. data/README.md +1 -1
  7. data/Rakefile +5 -1
  8. data/bin/init-cluster +13 -5
  9. data/couchbase.gemspec +2 -1
  10. data/examples/managing_query_indexes.rb +1 -1
  11. data/examples/managing_search_indexes.rb +62 -0
  12. data/examples/search.rb +187 -0
  13. data/ext/.clang-tidy +1 -0
  14. data/ext/build_version.hxx.in +1 -1
  15. data/ext/couchbase/bucket.hxx +0 -40
  16. data/ext/couchbase/couchbase.cxx +2578 -1368
  17. data/ext/couchbase/io/http_session.hxx +27 -7
  18. data/ext/couchbase/io/mcbp_parser.hxx +2 -0
  19. data/ext/couchbase/io/mcbp_session.hxx +53 -24
  20. data/ext/couchbase/io/session_manager.hxx +6 -1
  21. data/ext/couchbase/operations.hxx +13 -0
  22. data/ext/couchbase/operations/bucket_create.hxx +1 -0
  23. data/ext/couchbase/operations/bucket_drop.hxx +1 -0
  24. data/ext/couchbase/operations/bucket_flush.hxx +1 -0
  25. data/ext/couchbase/operations/bucket_get.hxx +1 -0
  26. data/ext/couchbase/operations/bucket_get_all.hxx +1 -0
  27. data/ext/couchbase/operations/bucket_update.hxx +1 -0
  28. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +1 -0
  29. data/ext/couchbase/operations/collection_create.hxx +6 -1
  30. data/ext/couchbase/operations/collection_drop.hxx +1 -0
  31. data/ext/couchbase/operations/command.hxx +86 -11
  32. data/ext/couchbase/operations/document_decrement.hxx +1 -0
  33. data/ext/couchbase/operations/document_exists.hxx +1 -0
  34. data/ext/couchbase/operations/document_get.hxx +1 -0
  35. data/ext/couchbase/operations/document_get_and_lock.hxx +1 -0
  36. data/ext/couchbase/operations/document_get_and_touch.hxx +1 -0
  37. data/ext/couchbase/operations/document_get_projected.hxx +243 -0
  38. data/ext/couchbase/operations/document_increment.hxx +4 -1
  39. data/ext/couchbase/operations/document_insert.hxx +1 -0
  40. data/ext/couchbase/operations/document_lookup_in.hxx +1 -0
  41. data/ext/couchbase/operations/document_mutate_in.hxx +1 -0
  42. data/ext/couchbase/operations/document_query.hxx +13 -2
  43. data/ext/couchbase/operations/document_remove.hxx +1 -0
  44. data/ext/couchbase/operations/document_replace.hxx +1 -0
  45. data/ext/couchbase/operations/document_search.hxx +337 -0
  46. data/ext/couchbase/operations/document_touch.hxx +1 -0
  47. data/ext/couchbase/operations/document_unlock.hxx +1 -0
  48. data/ext/couchbase/operations/document_upsert.hxx +1 -0
  49. data/ext/couchbase/operations/query_index_build_deferred.hxx +1 -0
  50. data/ext/couchbase/operations/query_index_create.hxx +1 -0
  51. data/ext/couchbase/operations/query_index_drop.hxx +1 -0
  52. data/ext/couchbase/operations/query_index_get_all.hxx +1 -0
  53. data/ext/couchbase/operations/scope_create.hxx +1 -0
  54. data/ext/couchbase/operations/scope_drop.hxx +1 -0
  55. data/ext/couchbase/operations/scope_get_all.hxx +2 -0
  56. data/ext/couchbase/operations/search_index.hxx +62 -0
  57. data/ext/couchbase/operations/search_index_analyze_document.hxx +92 -0
  58. data/ext/couchbase/operations/search_index_control_ingest.hxx +78 -0
  59. data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +80 -0
  60. data/ext/couchbase/operations/search_index_control_query.hxx +80 -0
  61. data/ext/couchbase/operations/search_index_drop.hxx +77 -0
  62. data/ext/couchbase/operations/search_index_get.hxx +80 -0
  63. data/ext/couchbase/operations/search_index_get_all.hxx +82 -0
  64. data/ext/couchbase/operations/search_index_get_documents_count.hxx +81 -0
  65. data/ext/couchbase/operations/search_index_upsert.hxx +106 -0
  66. data/ext/couchbase/protocol/client_opcode.hxx +10 -0
  67. data/ext/couchbase/protocol/cmd_get_collection_id.hxx +117 -0
  68. data/ext/couchbase/timeout_defaults.hxx +32 -0
  69. data/ext/couchbase/version.hxx +1 -1
  70. data/ext/test/main.cxx +5 -5
  71. data/lib/couchbase/binary_collection.rb +16 -12
  72. data/lib/couchbase/binary_collection_options.rb +4 -0
  73. data/lib/couchbase/cluster.rb +88 -8
  74. data/lib/couchbase/collection.rb +39 -15
  75. data/lib/couchbase/collection_options.rb +19 -2
  76. data/lib/couchbase/json_transcoder.rb +2 -2
  77. data/lib/couchbase/management/bucket_manager.rb +37 -23
  78. data/lib/couchbase/management/collection_manager.rb +15 -6
  79. data/lib/couchbase/management/query_index_manager.rb +16 -6
  80. data/lib/couchbase/management/search_index_manager.rb +61 -14
  81. data/lib/couchbase/search_options.rb +1492 -0
  82. data/lib/couchbase/version.rb +1 -1
  83. metadata +22 -2
@@ -0,0 +1,117 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <gsl/gsl_assert>
21
+
22
+ #include <protocol/client_opcode.hxx>
23
+ #include <protocol/status.hxx>
24
+ #include <protocol/cmd_info.hxx>
25
+
26
+ namespace couchbase::protocol
27
+ {
28
+
29
+ class get_collection_id_response_body
30
+ {
31
+ public:
32
+ static const inline client_opcode opcode = client_opcode::get_collection_id;
33
+
34
+ private:
35
+ std::uint64_t manifest_uid_;
36
+ std::uint32_t collection_uid_;
37
+
38
+ public:
39
+ [[nodiscard]] std::uint64_t manifest_uid()
40
+ {
41
+ return manifest_uid_;
42
+ }
43
+
44
+ [[nodiscard]] std::uint32_t collection_uid()
45
+ {
46
+ return collection_uid_;
47
+ }
48
+
49
+ bool parse(protocol::status status,
50
+ const header_buffer& header,
51
+ std::uint8_t framing_extras_size,
52
+ std::uint16_t key_size,
53
+ std::uint8_t extras_size,
54
+ const std::vector<uint8_t>& body,
55
+ const cmd_info&)
56
+ {
57
+ Expects(header[1] == static_cast<uint8_t>(opcode));
58
+ if (status == protocol::status::success && extras_size == 12) {
59
+ std::vector<uint8_t>::difference_type offset = framing_extras_size + key_size;
60
+
61
+ memcpy(&manifest_uid_, body.data() + offset, sizeof(manifest_uid_));
62
+ manifest_uid_ = utils::byte_swap_64(manifest_uid_);
63
+ offset += 8;
64
+
65
+ memcpy(&collection_uid_, body.data() + offset, sizeof(collection_uid_));
66
+ collection_uid_ = ntohl(collection_uid_);
67
+ return true;
68
+ }
69
+ return false;
70
+ }
71
+ };
72
+
73
+ class get_collection_id_request_body
74
+ {
75
+ public:
76
+ using response_body_type = get_collection_id_response_body;
77
+ static const inline client_opcode opcode = client_opcode::get_collection_id;
78
+
79
+ private:
80
+ std::string key_;
81
+
82
+ public:
83
+ void collection_path(const std::string& path)
84
+ {
85
+ key_ = path;
86
+ }
87
+
88
+ const std::string& key()
89
+ {
90
+ return key_;
91
+ }
92
+
93
+ const std::vector<std::uint8_t>& framing_extras()
94
+ {
95
+ static std::vector<std::uint8_t> empty;
96
+ return empty;
97
+ }
98
+
99
+ const std::vector<std::uint8_t>& extras()
100
+ {
101
+ static std::vector<std::uint8_t> empty;
102
+ return empty;
103
+ }
104
+
105
+ const std::vector<std::uint8_t>& value()
106
+ {
107
+ static std::vector<std::uint8_t> empty;
108
+ return empty;
109
+ }
110
+
111
+ std::size_t size()
112
+ {
113
+ return key_.size();
114
+ }
115
+ };
116
+
117
+ } // namespace couchbase::protocol
@@ -0,0 +1,32 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <chrono>
21
+
22
+ namespace couchbase::timeout_defaults
23
+ {
24
+ constexpr std::chrono::milliseconds connect_timeout{ 10'000 };
25
+ constexpr std::chrono::milliseconds key_value_timeout{ 2'500 };
26
+ constexpr std::chrono::milliseconds key_value_durable_timeout{ 10'000 };
27
+ constexpr std::chrono::milliseconds view_timeout{ 75'000 };
28
+ constexpr std::chrono::milliseconds query_timeout{ 75'000 };
29
+ constexpr std::chrono::milliseconds analytics_timeout{ 75'000 };
30
+ constexpr std::chrono::milliseconds search_timeout{ 75'000 };
31
+ constexpr std::chrono::milliseconds management_timeout{ 75'000 };
32
+ } // namespace couchbase::timeout_defaults
@@ -18,7 +18,7 @@
18
18
  #pragma once
19
19
 
20
20
  #define BACKEND_VERSION_MAJOR 0
21
- #define BACKEND_VERSION_MINOR 2
21
+ #define BACKEND_VERSION_MINOR 3
22
22
  #define BACKEND_VERSION_PATCH 0
23
23
 
24
24
  #include <build_version.hxx>
@@ -41,21 +41,21 @@ main()
41
41
  ruby_init_loadpath();
42
42
 
43
43
  rb_require(LIBCOUCHBASE_EXT_PATH);
44
+ rb_require("json");
44
45
  run_script(R"(
45
46
  p Couchbase::VERSION
46
47
  )");
47
48
 
48
49
  run_script(R"(
49
50
  B = Couchbase::Backend.new
50
- #B.open("192.168.42.101", "Administrator", "password")
51
51
  B.open("localhost", "Administrator", "password")
52
52
  )");
53
53
 
54
54
  run_script(R"(
55
- p B.open_bucket("default")
56
- p B.document_increment("default", "_default._default", "foo", {:initial_value => 32, :expiration => 42})
57
- p B.document_get("default", "_default._default", "foo")
58
- p B.document_decrement("default", "_default._default", "foo", {:initial_value => 32, :expiration => 42})
55
+ query = {
56
+ query: "hello"
57
+ }
58
+ p B.document_search("beers", JSON.generate(query), {})
59
59
  )");
60
60
 
61
61
  run_script(R"(
@@ -49,12 +49,14 @@ module Couchbase
49
49
  #
50
50
  # @return [CounterResult]
51
51
  def increment(id, options = IncrementOptions.new)
52
- resp = @backend.document_increment(@collection.bucket_name, "#{@collection.scope_name}.#{@collection.name}", id, {
53
- delta: options.delta,
54
- initial_value: options.initial,
55
- expiration: options.expiration,
56
- durability_level: options.durability_level,
57
- })
52
+ resp = @backend.document_increment(@collection.bucket_name, "#{@collection.scope_name}.#{@collection.name}", id,
53
+ options.timeout,
54
+ {
55
+ delta: options.delta,
56
+ initial_value: options.initial,
57
+ expiration: options.expiration,
58
+ durability_level: options.durability_level,
59
+ })
58
60
  CounterResult.new do |res|
59
61
  res.cas = resp[:cas]
60
62
  res.content = resp[:content]
@@ -69,12 +71,14 @@ module Couchbase
69
71
  #
70
72
  # @return [CounterResult]
71
73
  def decrement(id, options = DecrementOptions.new)
72
- resp = @backend.document_decrement(@collection.bucket_name, "#{@collection.scope_name}.#{@collection.name}", id, {
73
- delta: options.delta,
74
- initial_value: options.initial,
75
- expiration: options.expiration,
76
- durability_level: options.durability_level,
77
- })
74
+ resp = @backend.document_decrement(@collection.bucket_name, "#{@collection.scope_name}.#{@collection.name}", id,
75
+ options.timeout,
76
+ {
77
+ delta: options.delta,
78
+ initial_value: options.initial,
79
+ expiration: options.expiration,
80
+ durability_level: options.durability_level,
81
+ })
78
82
  CounterResult.new do |res|
79
83
  res.cas = resp[:cas]
80
84
  res.content = resp[:content]
@@ -20,6 +20,7 @@ module Couchbase
20
20
  # @return [Integer] The default CAS used (0 means no CAS in this context)
21
21
  attr_accessor :cas
22
22
 
23
+ # @yieldparam [AppendOptions] self
23
24
  def initialize
24
25
  yield self if block_given?
25
26
  end
@@ -29,6 +30,7 @@ module Couchbase
29
30
  # @return [Integer] The default CAS used (0 means no CAS in this context)
30
31
  attr_accessor :cas
31
32
 
33
+ # @yieldparam [PrependOptions] self
32
34
  def initialize
33
35
  yield self if block_given?
34
36
  end
@@ -47,6 +49,7 @@ module Couchbase
47
49
  # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
48
50
  attr_accessor :durability_level
49
51
 
52
+ # @yieldparam [IncrementOptions] self
50
53
  def initialize
51
54
  @delta = 1
52
55
  yield self if block_given?
@@ -73,6 +76,7 @@ module Couchbase
73
76
  # @return [:none, :majority, :majority_and_persist_to_active, :persist_to_majority] level of durability
74
77
  attr_accessor :durability_level
75
78
 
79
+ # @yieldparam [DecrementOptions] self
76
80
  def initialize
77
81
  @delta = 1
78
82
  yield self if block_given?
@@ -21,6 +21,8 @@ require "couchbase/management/query_index_manager"
21
21
  require "couchbase/management/analytics_index_manager"
22
22
  require "couchbase/management/search_index_manager"
23
23
 
24
+ require "couchbase/search_options"
25
+
24
26
  module Couchbase
25
27
  class Cluster
26
28
  alias_method :inspect, :to_s
@@ -110,8 +112,92 @@ module Couchbase
110
112
  # @param [SearchQuery] query the query tree
111
113
  # @param [SearchOptions] options the query tree
112
114
  #
113
- # @return [QueryResult]
114
- def search_query(index_name, query, options = SearchOptions.new) end
115
+ # @return [SearchResult]
116
+ def search_query(index_name, query, options = SearchOptions.new)
117
+ resp = @backend.document_search(index_name, JSON.generate(query), {
118
+ timeout: options.timeout,
119
+ limit: options.limit,
120
+ skip: options.skip,
121
+ explain: options.explain,
122
+ highlight_style: options.highlight_style,
123
+ highlight_fields: options.highlight_fields,
124
+ fields: options.fields,
125
+ sort: options.sort&.map { |v| JSON.generate(v) },
126
+ facets: options.facets&.map { |(k, v)| [k, JSON.generate(v)] },
127
+ scan_consistency: options.instance_variable_get("@scan_consistency"),
128
+ mutation_state: options.instance_variable_get("@mutation_state")&.tokens&.map { |t|
129
+ {
130
+ bucket_name: t.bucket_name,
131
+ partition_id: t.partition_id,
132
+ partition_uuid: t.partition_uuid,
133
+ sequence_number: t.sequence_number,
134
+ }
135
+ },
136
+ })
137
+
138
+ SearchResult.new do |res|
139
+ res.meta_data = SearchMetaData.new do |meta|
140
+ meta.metrics.max_score = resp[:meta_data][:metrics][:max_score]
141
+ meta.metrics.error_partition_count = resp[:meta_data][:metrics][:error_partition_count]
142
+ meta.metrics.success_partition_count = resp[:meta_data][:metrics][:success_partition_count]
143
+ meta.metrics.took = resp[:meta_data][:metrics][:took]
144
+ meta.metrics.total_rows = resp[:meta_data][:metrics][:total_rows]
145
+ end
146
+ res.rows = resp[:rows].map do |r|
147
+ SearchRow.new do |row|
148
+ row.transcoder = options.transcoder
149
+ row.index = r[:index]
150
+ row.id = r[:id]
151
+ row.score = r[:score]
152
+ row.fragments = r[:fragments]
153
+ row.locations = SearchRowLocations.new(
154
+ r[:locations].map do |loc|
155
+ SearchRowLocation.new do |location|
156
+ location.field = loc[:field]
157
+ location.term = loc[:term]
158
+ location.position = loc[:position]
159
+ location.start_offset = loc[:start_offset]
160
+ location.end_offset = loc[:end_offset]
161
+ location.array_positions = loc[:array_positions]
162
+ end
163
+ end
164
+ )
165
+ row.instance_variable_set("@fields", r[:fields])
166
+ row.explanation = JSON.parse(r[:explanation]) if r[:explanation]
167
+ end
168
+ end
169
+ res.facets = resp[:facets]&.each_with_object({}) do |(k, v), o|
170
+ facet = case options.facets[k]
171
+ when SearchFacet::SearchFacetTerm
172
+ SearchFacetResult::TermFacetResult.new do |f|
173
+ f.terms = v[:terms]&.map do |t|
174
+ SearchFacetResult::TermFacetResult::TermFacet.new(t[:term], t[:count])
175
+ end || []
176
+ end
177
+ when SearchFacet::SearchFacetDateRange
178
+ SearchFacetResult::DateRangeFacetResult.new do |f|
179
+ f.date_ranges = v[:date_ranges]&.map do |r|
180
+ SearchFacetResult::DateRangeFacetResult::DateRangeFacet.new(r[:name], r[:count], r[:start_time], r[:end_time])
181
+ end || []
182
+ end
183
+ when SearchFacet::SearchFacetNumericRange
184
+ SearchFacetResult::NumericRangeFacetResult.new do |f|
185
+ f.numeric_ranges = v[:numeric_ranges]&.map do |r|
186
+ SearchFacetResult::NumericRangeFacetResult::NumericRangeFacet.new(r[:name], r[:count], r[:min], r[:max])
187
+ end || []
188
+ end
189
+ else
190
+ next # ignore unknown facet result
191
+ end
192
+ facet.name = v[:name]
193
+ facet.field = v[:field]
194
+ facet.total = v[:total]
195
+ facet.missing = v[:missing]
196
+ facet.other = v[:other]
197
+ o[k] = facet
198
+ end
199
+ end
200
+ end
115
201
 
116
202
  # @return [Management::UserManager]
117
203
  def users
@@ -361,12 +447,6 @@ module Couchbase
361
447
  end
362
448
  end
363
449
 
364
- class SearchOptions
365
- def initialize
366
- yield self if block_given?
367
- end
368
- end
369
-
370
450
  class DiagnosticsOptions
371
451
  # @return [String] Holds custom report id.
372
452
  attr_accessor :report_id
@@ -49,12 +49,21 @@ module Couchbase
49
49
  #
50
50
  # @return [GetResult]
51
51
  def get(id, options = GetOptions.new)
52
- resp = @backend.document_get(bucket_name, "#{@scope_name}.#{@name}", id)
52
+ resp = if options.need_projected_get?
53
+ @backend.document_get_projected(bucket_name, "#{@scope_name}.#{@name}", id,
54
+ options.timeout,
55
+ options.with_expiration,
56
+ options.projections,
57
+ options.preserve_array_indexes)
58
+ else
59
+ @backend.document_get(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout)
60
+ end
53
61
  GetResult.new do |res|
54
62
  res.transcoder = options.transcoder
55
63
  res.cas = resp[:cas]
56
64
  res.flags = resp[:flags]
57
65
  res.encoded = resp[:content]
66
+ res.expiration = resp[:expiration] if resp.key?(:expiration)
58
67
  end
59
68
  end
60
69
 
@@ -66,7 +75,7 @@ module Couchbase
66
75
  #
67
76
  # @return [GetResult]
68
77
  def get_and_lock(id, lock_time, options = GetAndLockOptions.new)
69
- resp = @backend.document_get_and_lock(bucket_name, "#{@scope_name}.#{@name}", id, lock_time)
78
+ resp = @backend.document_get_and_lock(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, lock_time)
70
79
  GetResult.new do |res|
71
80
  res.transcoder = options.transcoder
72
81
  res.cas = resp[:cas]
@@ -83,7 +92,7 @@ module Couchbase
83
92
  #
84
93
  # @return [GetResult]
85
94
  def get_and_touch(id, expiration, options = GetAndTouchOptions.new)
86
- resp = @backend.document_get_and_touch(bucket_name, "#{@scope_name}.#{@name}", id, expiration)
95
+ resp = @backend.document_get_and_touch(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, expiration)
87
96
  GetResult.new do |res|
88
97
  res.transcoder = options.transcoder
89
98
  res.cas = resp[:cas]
@@ -115,7 +124,7 @@ module Couchbase
115
124
  #
116
125
  # @return [ExistsResult]
117
126
  def exists(id, options = ExistsOptions.new)
118
- resp = @backend.document_exists(bucket_name, "#{@scope_name}.#{@name}", id)
127
+ resp = @backend.document_exists(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout)
119
128
  ExistsResult.new do |res|
120
129
  res.status = resp[:status]
121
130
  res.partition_id = resp[:partition_id]
@@ -130,7 +139,7 @@ module Couchbase
130
139
  #
131
140
  # @return [MutationResult]
132
141
  def remove(id, options = RemoveOptions.new)
133
- resp = @backend.document_remove(bucket_name, "#{@scope_name}.#{@name}", id, {
142
+ resp = @backend.document_remove(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, {
134
143
  durability_level: options.durability_level
135
144
  })
136
145
  MutationResult.new do |res|
@@ -148,7 +157,7 @@ module Couchbase
148
157
  # @return [MutationResult]
149
158
  def insert(id, content, options = InsertOptions.new)
150
159
  blob, flags = options.transcoder.encode(content)
151
- resp = @backend.document_insert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
160
+ resp = @backend.document_insert(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, blob, flags, {
152
161
  durability_level: options.durability_level,
153
162
  expiration: options.expiration,
154
163
  })
@@ -167,7 +176,7 @@ module Couchbase
167
176
  # @return [MutationResult]
168
177
  def upsert(id, content, options = UpsertOptions.new)
169
178
  blob, flags = options.transcoder.encode(content)
170
- resp = @backend.document_upsert(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
179
+ resp = @backend.document_upsert(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, blob, flags, {
171
180
  durability_level: options.durability_level,
172
181
  expiration: options.expiration,
173
182
  })
@@ -186,7 +195,7 @@ module Couchbase
186
195
  # @return [MutationResult]
187
196
  def replace(id, content, options = ReplaceOptions.new)
188
197
  blob, flags = options.transcoder.encode(content)
189
- resp = @backend.document_replace(bucket_name, "#{@scope_name}.#{@name}", id, blob, flags, {
198
+ resp = @backend.document_replace(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, blob, flags, {
190
199
  durability_level: options.durability_level,
191
200
  expiration: options.expiration,
192
201
  cas: options.cas,
@@ -205,7 +214,7 @@ module Couchbase
205
214
  #
206
215
  # @return [MutationResult]
207
216
  def touch(id, expiration, options = TouchOptions.new)
208
- resp = @backend.document_touch(bucket_name, "#{@scope_name}.#{@name}", id, expiration)
217
+ resp = @backend.document_touch(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, expiration)
209
218
  MutationResult.new do |res|
210
219
  res.cas = resp[:cas]
211
220
  end
@@ -219,7 +228,7 @@ module Couchbase
219
228
  #
220
229
  # @raise [Error::DocumentNotFound]
221
230
  def unlock(id, cas, options = UnlockOptions.new)
222
- @backend.document_unlock(bucket_name, "#{@scope_name}.#{@name}", id, cas)
231
+ @backend.document_unlock(bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, cas)
223
232
  end
224
233
 
225
234
  # Performs lookups to document fragments
@@ -231,8 +240,14 @@ module Couchbase
231
240
  # @return [LookupInResult]
232
241
  def lookup_in(id, specs, options = LookupInOptions.new)
233
242
  resp = @backend.document_lookup_in(
234
- bucket_name, "#{@scope_name}.#{@name}", id, options.access_deleted,
235
- specs.map { |s| {opcode: s.type, xattr: s.xattr?, path: s.path} }
243
+ bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, options.access_deleted,
244
+ specs.map { |s|
245
+ {
246
+ opcode: s.type,
247
+ xattr: s.xattr?,
248
+ path: s.path
249
+ }
250
+ }
236
251
  )
237
252
  LookupInResult.new do |res|
238
253
  res.transcoder = options.transcoder
@@ -258,9 +273,18 @@ module Couchbase
258
273
  # @return [MutateInResult]
259
274
  def mutate_in(id, specs, options = MutateInOptions.new)
260
275
  resp = @backend.document_mutate_in(
261
- bucket_name, "#{@scope_name}.#{@name}", id, options.access_deleted,
262
- specs.map { |s| {opcode: s.type, path: s.path, param: s.param,
263
- xattr: s.xattr?, expand_macros: s.expand_macros?, create_parents: s.create_parents?} }, {
276
+ bucket_name, "#{@scope_name}.#{@name}", id, options.timeout, options.access_deleted,
277
+ specs.map { |s|
278
+ {
279
+ opcode: s.type,
280
+ path: s.path,
281
+ param: s.param,
282
+ xattr: s.xattr?,
283
+ expand_macros: s.expand_macros?,
284
+ create_parents: s.create_parents?
285
+ }
286
+ },
287
+ {
264
288
  durability_level: options.durability_level
265
289
  }
266
290
  )