couchbase 3.4.3-arm64-darwin-20 → 3.4.4-arm64-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7781858dae225372665d58fecb6eccadbd09828de8324398143a6233ac2b8a26
4
- data.tar.gz: 5f9886de965d9fc967e7c241cff4cffd284002e491e8438b42a054dbcacf7571
3
+ metadata.gz: 114c1f905e9873c1e6c8ae96badf29c0c795c9dc653a66584ec41415b5a504c3
4
+ data.tar.gz: 7993c632a1513ab6359a91063bc22ce8aaf6402be1353f0fb0f7c2a975f5e57d
5
5
  SHA512:
6
- metadata.gz: da37e980f2852accdaa22c27e214b8a1e9cc6edb5fd690a9c57c5b8db3daddb180b40e34fb4acdd25df5b76292f6a5b3fb158edad4d6ce5f27ea2877c08e90fd
7
- data.tar.gz: 4c2e1d4aa7ae3f60dacd18e2edcf299ceca355c6f4b2a84264bf928df09e418a0484868a93f7166c89ad53d0b048637ccde0e4e33d608351f69102c11198cb93
6
+ metadata.gz: 8220a5639d0c7b74b2a6376371ef495239178a49f29b836a6f902569c7f0491ab7df09fb6e049639ed7e6aeb21ee9c6fac145208cfff23095cc428cd1b12651b
7
+ data.tar.gz: 42c503acdc73e22ad85f346e56e47b7edc0d8b30c5887a5d8b2d2280e8e1edd288f19e09d8c1c294f422a559fb5970d8d6257e292aafb2045260fbd831ae5483
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![license](https://img.shields.io/github/license/couchbase/couchbase-ruby-client?color=brightgreen)](https://opensource.org/licenses/Apache-2.0)
4
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)
5
+ [![commits](https://img.shields.io/github/commits-since/couchbase/couchbase-ruby-client/latest?color=brightgreen)](https://github.com/couchbase/couchbase-ruby-client/commits/main)
6
6
  [![linters](https://img.shields.io/github/actions/workflow/status/couchbase/couchbase-ruby-client/linters.yml?branch=main&label=linters)](https://github.com/couchbase/couchbase-ruby-client/actions?query=workflow%3Alinters)
7
7
 
8
8
  This repository contains the third generation of the official Couchbase SDK for Ruby (aka. SDKv3)
@@ -23,7 +23,7 @@ The library has been tested with MRI 3.0, 3.1 and 3.2. Supported platforms are L
23
23
  Add this line to your application's Gemfile:
24
24
 
25
25
  ```ruby
26
- gem "couchbase", "3.4.3"
26
+ gem "couchbase", "3.4.4"
27
27
  ```
28
28
 
29
29
  And then execute:
@@ -124,7 +124,7 @@ module Couchbase
124
124
  metrics.warning_count = resp[:meta][:metrics][:warning_count]
125
125
  end
126
126
  end
127
- res[:warnings] = resp[:warnings].map { |warn| QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
127
+ meta.warnings = resp[:warnings].map { |warn| QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
128
128
  end
129
129
  res.instance_variable_set(:@rows, resp[:rows])
130
130
  end
@@ -15,6 +15,7 @@
15
15
  require "couchbase/errors"
16
16
  require "couchbase/collection_options"
17
17
  require "couchbase/binary_collection"
18
+ require "couchbase/key_value_scan"
18
19
 
19
20
  module Couchbase
20
21
  # Provides access to all collection APIs
@@ -481,11 +482,68 @@ module Couchbase
481
482
  f.index = field[:index]
482
483
  f.path = field[:path]
483
484
  f.value = field[:value]
485
+ f.error = field[:error]
484
486
  end
485
487
  end
486
488
  end
487
489
  end
488
490
 
491
+ # Performs lookups to document fragments. Reads from the active node and all available replicas and returns the
492
+ # first result found
493
+ #
494
+ # @param [String] id the document id which is used to uniquely identify it.
495
+ # @param [Array<LookupInSpec>] specs the list of specifications which describe the types of the lookups to perform
496
+ # @param [Options::LookupInAnyReplica] options request customization
497
+ #
498
+ # @return [LookupInReplicaResult]
499
+ #
500
+ # @raise [Error::DocumentIrretrievable]
501
+ # @raise [Error::Timeout]
502
+ # @raise [Error::CouchbaseError]
503
+ # @raise [Error::FeatureNotAvailable]
504
+ def lookup_in_any_replica(id, specs, options = Options::LookupInAnyReplica::DEFAULT)
505
+ resp = @backend.document_lookup_in_any_replica(
506
+ bucket_name, @scope_name, @name, id,
507
+ specs.map do |s|
508
+ {
509
+ opcode: s.type,
510
+ xattr: s.xattr?,
511
+ path: s.path,
512
+ }
513
+ end, options.to_backend
514
+ )
515
+ extract_lookup_in_replica_result(resp, options)
516
+ end
517
+
518
+ # Performs lookups to document fragments. Reads from the active node and all available replicas and returns all of
519
+ # the results
520
+ #
521
+ # @param [String] id the document id which is used to uniquely identify it.
522
+ # @param [Array<LookupInSpec>] specs the list of specifications which describe the types of the lookups to perform
523
+ # @param [Options::LookupInAllReplicas] options request customization
524
+ #
525
+ # @return [Array<LookupInReplicaResult>]
526
+ #
527
+ # @raise [Error::DocumentNotFound]
528
+ # @raise [Error::Timeout]
529
+ # @raise [Error::CouchbaseError]
530
+ # @raise [Error::FeatureNotAvailable]
531
+ def lookup_in_all_replicas(id, specs, options = Options::LookupInAllReplicas::DEFAULT)
532
+ resp = @backend.document_lookup_in_all_replicas(
533
+ bucket_name, @scope_name, @name, id,
534
+ specs.map do |s|
535
+ {
536
+ opcode: s.type,
537
+ xattr: s.xattr?,
538
+ path: s.path,
539
+ }
540
+ end, options.to_backend
541
+ )
542
+ resp.map do |entry|
543
+ extract_lookup_in_replica_result(entry, options)
544
+ end
545
+ end
546
+
489
547
  # Performs mutations to document fragments
490
548
  #
491
549
  # @param [String] id the document id which is used to uniquely identify it.
@@ -535,6 +593,38 @@ module Couchbase
535
593
  end
536
594
  end
537
595
 
596
+ # Performs a key-value scan operation on the collection
597
+ #
598
+ # @api uncommitted
599
+ #
600
+ # @param [RangeScan, PrefixScan, SamplingScan] scan_type the type of the scan
601
+ # @param [Options::Scan] options request customization
602
+ #
603
+ # @example Get a sample of up to 5 documents from the collection and store their IDs in an array
604
+ # result = collection.scan(SamplingScan.new(5), Options::Scan.new(ids_only: true))
605
+ # ids = result.map { |item| item.id }
606
+ #
607
+ # @example Get all documents whose ID starts with 'customer_1' and output their content
608
+ # result = collection.scan(PrefixScan.new("customer_1"))
609
+ # result.each { |item| puts item.content }
610
+ #
611
+ # @example Get all documents with ID between 'customer_1' and 'customer_2', excluding 'customer_2' and output their content
612
+ # result = collection.scan(RangeScan.new(
613
+ # from: ScanTerm.new("customer_1"),
614
+ # to: ScanTerm.new("customer_2", exclusive: true)
615
+ # ))
616
+ # result.each { |item| puts item.content }
617
+ #
618
+ # @return [ScanResults]
619
+ def scan(scan_type, options = Options::Scan::DEFAULT)
620
+ ScanResults.new(
621
+ core_scan_result: @backend.document_scan_create(
622
+ @bucket_name, @scope_name, @name, scan_type.to_backend, options.to_backend
623
+ ),
624
+ transcoder: options.transcoder
625
+ )
626
+ end
627
+
538
628
  private
539
629
 
540
630
  def extract_mutation_token(resp)
@@ -548,6 +638,24 @@ module Couchbase
548
638
  end
549
639
  end
550
640
 
641
+ def extract_lookup_in_replica_result(resp, options)
642
+ LookupInReplicaResult.new do |res|
643
+ res.transcoder = options.transcoder
644
+ res.cas = resp[:cas]
645
+ res.deleted = resp[:deleted]
646
+ res.is_replica = resp[:is_replica]
647
+ res.encoded = resp[:fields].map do |field|
648
+ SubDocumentField.new do |f|
649
+ f.exists = field[:exists]
650
+ f.index = field[:index]
651
+ f.path = field[:path]
652
+ f.value = field[:value]
653
+ f.error = field[:error]
654
+ end
655
+ end
656
+ end
657
+ end
658
+
551
659
  # @api private
552
660
  # TODO: deprecate in 3.1
553
661
  GetOptions = ::Couchbase::Options::Get
@@ -15,6 +15,9 @@
15
15
  require "rubygems/deprecate"
16
16
 
17
17
  require "couchbase/json_transcoder"
18
+ require "couchbase/raw_string_transcoder"
19
+ require "couchbase/raw_json_transcoder"
20
+ require "couchbase/raw_binary_transcoder"
18
21
  require "couchbase/subdoc"
19
22
  require "couchbase/mutation_state"
20
23
 
@@ -164,6 +167,8 @@ module Couchbase
164
167
  # @return [Object] the decoded
165
168
  def content(path_or_index, transcoder = self.transcoder)
166
169
  field = get_field_at_index(path_or_index)
170
+
171
+ raise field.error unless field.error.nil?
167
172
  raise Error::PathNotFound, "Path is not found: #{path_or_index}" unless field.exists
168
173
 
169
174
  transcoder.decode(field.value, :json)
@@ -186,6 +191,8 @@ module Couchbase
186
191
  end
187
192
  return false unless field
188
193
 
194
+ raise field.error unless field.error.nil?
195
+
189
196
  field.exists
190
197
  end
191
198
 
@@ -227,6 +234,18 @@ module Couchbase
227
234
  end
228
235
  end
229
236
 
237
+ class LookupInReplicaResult < LookupInResult
238
+ # @return [Boolean] true if the document was read from a replica node
239
+ attr_accessor :is_replica
240
+ alias replica? is_replica
241
+
242
+ # @yieldparam [LookupInReplicaResult] self
243
+ def initialize
244
+ super
245
+ yield self if block_given?
246
+ end
247
+ end
248
+
230
249
  class MutateInResult < MutationResult
231
250
  # Decodes the content at the given index
232
251
  #
@@ -291,10 +310,91 @@ module Couchbase
291
310
  # @return [String] path
292
311
  attr_accessor :path
293
312
 
313
+ # @return [CouchbaseError] error
314
+ attr_accessor :error
315
+
294
316
  # @yieldparam [SubDocumentField] self
295
317
  def initialize
296
318
  yield self if block_given?
297
319
  end
298
320
  end
321
+
322
+ class ScanResult
323
+ # @return [String] identifier of the document
324
+ attr_accessor :id
325
+
326
+ # @return [Boolean] whether only ids are returned from this scan
327
+ attr_accessor :id_only
328
+
329
+ # @return [Integer, nil] holds the CAS value of the fetched document
330
+ attr_accessor :cas
331
+
332
+ # @return [Integer, nil] the expiration if fetched and present
333
+ attr_accessor :expiry
334
+
335
+ # @return [JsonTranscoder, RawBinaryTranscoder, RawJsonTranscoder, RawStringTranscoder, #decode] The default
336
+ # transcoder which should be used
337
+ attr_accessor :transcoder
338
+
339
+ def initialize(id:, id_only:, cas: nil, expiry: nil, encoded: nil, flags: nil, transcoder: JsonTranscoder.new)
340
+ @id = id
341
+ @id_only = id_only
342
+ @cas = cas
343
+ @expiry = expiry
344
+ @encoded = encoded
345
+ @flags = flags
346
+ @transcoder = transcoder
347
+
348
+ yield self if block_given?
349
+ end
350
+
351
+ # Decodes the content of the document using given (or default transcoder)
352
+ #
353
+ # @param [JsonTranscoder, RawJsonTranscoder, RawBinaryTranscoder, RawStringTranscoder] transcoder custom transcoder
354
+ #
355
+ # @return [Object, nil]
356
+ def content(transcoder = self.transcoder)
357
+ return nil if @encoded.nil?
358
+
359
+ transcoder ? transcoder.decode(@encoded, @flags) : @encoded
360
+ end
361
+ end
362
+
363
+ class ScanResults
364
+ include Enumerable
365
+
366
+ def initialize(core_scan_result:, transcoder:)
367
+ @core_scan_result = core_scan_result
368
+ @transcoder = transcoder
369
+ end
370
+
371
+ def each
372
+ return enum_for(:each) unless block_given?
373
+
374
+ loop do
375
+ resp = @core_scan_result.next_item
376
+
377
+ break if resp.nil?
378
+
379
+ if resp[:id_only]
380
+ yield ScanResult.new(
381
+ id: resp[:id],
382
+ id_only: resp[:id_only],
383
+ transcoder: @transcoder
384
+ )
385
+ else
386
+ yield ScanResult.new(
387
+ id: resp[:id],
388
+ id_only: resp[:id_only],
389
+ cas: resp[:cas],
390
+ expiry: resp[:expiry],
391
+ encoded: resp[:encoded],
392
+ flags: resp[:flags],
393
+ transcoder: @transcoder
394
+ )
395
+ end
396
+ end
397
+ end
398
+ end
299
399
  end
300
400
  end
@@ -183,6 +183,11 @@ module Couchbase
183
183
  class DurableWriteReCommitInProgress < CouchbaseError
184
184
  end
185
185
 
186
+ # Happens when consistency requirements are specified but the partition uuid of the requirements do not align
187
+ # with the server
188
+ class MutationTokenOutdated < CouchbaseError
189
+ end
190
+
186
191
  # Subdocument exception thrown when a path does not exist in the document. The exact meaning of path existence
187
192
  # depends on the operation and inputs.
188
193
  class PathNotFound < CouchbaseError
@@ -0,0 +1,125 @@
1
+ # Copyright 2023. Couchbase, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Couchbase
16
+ # A scan term used to specify the bounds of a range scan
17
+ class ScanTerm
18
+ attr_accessor :term # @return [ScanTerm]
19
+ attr_accessor :exclusive # @return [Boolean]
20
+
21
+ # Creates an instance of a ScanTerm
22
+ #
23
+ # @api uncommitted
24
+ #
25
+ # @param [String] term the key pattern of this term
26
+ # @param [Boolean] exclusive specifies if this term is excluded while scanning, the bounds are included by default
27
+ def initialize(term, exclusive: false)
28
+ @term = term
29
+ @exclusive = exclusive
30
+ end
31
+
32
+ # @api private
33
+ def to_backend
34
+ {
35
+ term: @term,
36
+ exclusive: @exclusive,
37
+ }
38
+ end
39
+ end
40
+
41
+ # A range scan performs a scan on a range of keys
42
+ class RangeScan
43
+ attr_accessor :from # @return [ScanTerm, nil]
44
+ attr_accessor :to # @return [ScanTerm, nil]
45
+
46
+ # Creates an instance of a RangeScan scan type
47
+ #
48
+ # @api uncommitted
49
+ #
50
+ # @param [ScanTerm, String, nil] from the lower bound of the range, if set
51
+ # @param [ScanTerm, String, nil] to the upper bound of the range, if set
52
+ def initialize(from: nil, to: nil)
53
+ @from =
54
+ if from.nil? || from.instance_of?(ScanTerm)
55
+ from
56
+ else
57
+ ScanTerm(from)
58
+ end
59
+ @to =
60
+ if to.nil? || to.instance_of?(ScanTerm)
61
+ to
62
+ else
63
+ ScanTerm(to)
64
+ end
65
+ end
66
+
67
+ # @api private
68
+ def to_backend
69
+ {
70
+ scan_type: :range,
71
+ from: @from&.to_backend,
72
+ to: @to&.to_backend,
73
+ }
74
+ end
75
+ end
76
+
77
+ # A prefix scan performs a scan that includes all documents whose keys start with the given prefix
78
+ class PrefixScan
79
+ attr_accessor :prefix # @return [String]
80
+
81
+ # Creates an instance of a PrefixScan scan type
82
+ #
83
+ # @api uncommitted
84
+ #
85
+ # @param [String, nil] prefix the prefix all document keys should start with
86
+ def initialize(prefix)
87
+ @prefix = prefix
88
+ end
89
+
90
+ # @api private
91
+ def to_backend
92
+ {
93
+ scan_type: :prefix,
94
+ prefix: @prefix,
95
+ }
96
+ end
97
+ end
98
+
99
+ # A sampling scan performs a scan that randomly selects documents up to a configured limit
100
+ class SamplingScan
101
+ attr_accessor :limit # @return [Integer]
102
+ attr_accessor :seed # @return [Integer, nil]
103
+
104
+ # Creates an instance of a SamplingScan scan type
105
+ #
106
+ # @api uncommitted
107
+ #
108
+ # @param [Integer] limit the maximum number of documents the sampling scan can return
109
+ # @param [Integer, nil] seed the seed used for the random number generator that selects the documents. If not set,
110
+ # a seed is generated at random
111
+ def initialize(limit, seed = nil)
112
+ @limit = limit
113
+ @seed = seed
114
+ end
115
+
116
+ # @api private
117
+ def to_backend
118
+ {
119
+ scan_type: :sampling,
120
+ limit: @limit,
121
+ seed: @seed,
122
+ }
123
+ end
124
+ end
125
+ end
Binary file
@@ -1026,6 +1026,151 @@ module Couchbase
1026
1026
  DEFAULT = LookupIn.new.freeze
1027
1027
  end
1028
1028
 
1029
+ # Options for {Collection#lookup_in_any_replica}
1030
+ class LookupInAnyReplica < Base
1031
+ attr_accessor :transcoder # @return [JsonTranscoder, #decode(String)]
1032
+
1033
+ # Creates an instance of options for {Collection#lookup_in_any_replica}
1034
+ #
1035
+ # @param [JsonTranscoder, #decode(String)] transcoder used for encoding
1036
+ #
1037
+ # @param [Integer, #in_milliseconds, nil] timeout
1038
+ # @param [Proc, nil] retry_strategy the custom retry strategy, if set
1039
+ # @param [Hash, nil] client_context the client context data, if set
1040
+ # @param [Span, nil] parent_span if set holds the parent span, that should be used for this request
1041
+ #
1042
+ # @yieldparam [LookupIn] self
1043
+ def initialize(transcoder: JsonTranscoder.new,
1044
+ timeout: nil,
1045
+ retry_strategy: nil,
1046
+ client_context: nil,
1047
+ parent_span: nil)
1048
+ super(timeout: timeout, retry_strategy: retry_strategy, client_context: client_context, parent_span: parent_span)
1049
+ @transcoder = transcoder
1050
+ yield self if block_given?
1051
+ end
1052
+
1053
+ # @api private
1054
+ def to_backend
1055
+ {
1056
+ timeout: Utils::Time.extract_duration(@timeout),
1057
+ }
1058
+ end
1059
+
1060
+ # @api private
1061
+ # @return [Boolean]
1062
+ attr_accessor :access_deleted
1063
+
1064
+ # @api private
1065
+ DEFAULT = LookupInAnyReplica.new.freeze
1066
+ end
1067
+
1068
+ # Options for {Collection#lookup_in_all_replicas}
1069
+ class LookupInAllReplicas < Base
1070
+ attr_accessor :transcoder # @return [JsonTranscoder, #decode(String)]
1071
+
1072
+ # Creates an instance of options for {Collection#lookup_in_all_replicas}
1073
+ #
1074
+ # @param [JsonTranscoder, #decode(String)] transcoder used for encoding
1075
+ #
1076
+ # @param [Integer, #in_milliseconds, nil] timeout
1077
+ # @param [Proc, nil] retry_strategy the custom retry strategy, if set
1078
+ # @param [Hash, nil] client_context the client context data, if set
1079
+ # @param [Span, nil] parent_span if set holds the parent span, that should be used for this request
1080
+ #
1081
+ # @yieldparam [LookupInAllReplicas] self
1082
+ def initialize(transcoder: JsonTranscoder.new,
1083
+ timeout: nil,
1084
+ retry_strategy: nil,
1085
+ client_context: nil,
1086
+ parent_span: nil)
1087
+ super(timeout: timeout, retry_strategy: retry_strategy, client_context: client_context, parent_span: parent_span)
1088
+ @transcoder = transcoder
1089
+ yield self if block_given?
1090
+ end
1091
+
1092
+ # @api private
1093
+ def to_backend
1094
+ {
1095
+ timeout: Utils::Time.extract_duration(@timeout),
1096
+ }
1097
+ end
1098
+
1099
+ # @api private
1100
+ DEFAULT = LookupInAllReplicas.new.freeze
1101
+ end
1102
+
1103
+ # Options for {Collection#scan}
1104
+ class Scan < Base
1105
+ attr_accessor :ids_only # @return [Boolean]
1106
+ attr_accessor :transcoder # @return [JsonTranscoder, #decode(String)]
1107
+ attr_accessor :mutation_state # @return [MutationState, nil]
1108
+ attr_accessor :batch_byte_limit # @return [Integer, nil]
1109
+ attr_accessor :batch_item_limit # @return [Integer, nil]
1110
+ attr_accessor :concurrency # @return [Integer, nil]
1111
+
1112
+ # Creates an instance of options for {Collection#scan}
1113
+ #
1114
+ # @param [Boolean] ids_only if set to true, the content of the documents is not included in the results
1115
+ # @param [JsonTranscoder, #decode(String)] transcoder used for decoding
1116
+ # @param [MutationState, nil] mutation_state sets the mutation tokens this scan should be consistent with
1117
+ # @param [Integer, nil] batch_byte_limit allows to limit the maximum amount of bytes that are sent from the server
1118
+ # to the client on each partition batch, defaults to 15,000
1119
+ # @param [Integer, nil] batch_item_limit allows to limit the maximum amount of items that are sent from the server
1120
+ # to the client on each partition batch, defaults to 50
1121
+ # @param [Integer, nil] concurrency specifies the maximum number of partitions that can be scanned concurrently,
1122
+ # defaults to 1
1123
+ #
1124
+ # @param [Integer, #in_milliseconds, nil] timeout
1125
+ # @param [Proc, nil] retry_strategy the custom retry strategy, if set
1126
+ # @param [Hash, nil] client_context the client context data, if set
1127
+ # @param [Span, nil] parent_span if set holds the parent span, that should be used for this request
1128
+ #
1129
+ # @yieldparam [LookupIn] self
1130
+ def initialize(ids_only: false,
1131
+ transcoder: JsonTranscoder.new,
1132
+ mutation_state: nil,
1133
+ batch_byte_limit: nil,
1134
+ batch_item_limit: nil,
1135
+ concurrency: nil,
1136
+ timeout: nil,
1137
+ retry_strategy: nil,
1138
+ client_context: nil,
1139
+ parent_span: nil)
1140
+ super(timeout: timeout, retry_strategy: retry_strategy, client_context: client_context, parent_span: parent_span)
1141
+ @ids_only = ids_only
1142
+ @transcoder = transcoder
1143
+ @mutation_state = mutation_state
1144
+ @batch_byte_limit = batch_byte_limit
1145
+ @batch_item_limit = batch_item_limit
1146
+ @concurrency = concurrency
1147
+ yield self if block_given?
1148
+ end
1149
+
1150
+ # Sets the mutation tokens this query should be consistent with
1151
+ #
1152
+ # @note overrides consistency level set by {#scan_consistency=}
1153
+ #
1154
+ # @param [MutationState] mutation_state the mutation state containing the mutation tokens
1155
+ def consistent_with(mutation_state)
1156
+ @mutation_state = mutation_state
1157
+ end
1158
+
1159
+ # @api private
1160
+ def to_backend
1161
+ {
1162
+ timeout: Utils::Time.extract_duration(@timeout),
1163
+ ids_only: @ids_only,
1164
+ mutation_state: @mutation_state.to_a,
1165
+ batch_byte_limit: @batch_byte_limit,
1166
+ batch_item_limit: @batch_item_limit,
1167
+ concurrency: @concurrency,
1168
+ }
1169
+ end
1170
+
1171
+ DEFAULT = Scan.new.freeze
1172
+ end
1173
+
1029
1174
  # Options for {BinaryCollection#append}
1030
1175
  class Append < Base
1031
1176
  attr_accessor :cas # @return [Integer]
@@ -1849,6 +1994,7 @@ module Couchbase
1849
1994
  attr_accessor :profile # @return [Symbol]
1850
1995
  attr_accessor :flex_index # @return [Boolean]
1851
1996
  attr_accessor :preserve_expiry # @return [Boolean]
1997
+ attr_accessor :use_replica # @return [Boolean, nil]
1852
1998
  attr_accessor :scope_qualifier # @return [String]
1853
1999
  attr_accessor :transcoder # @return [JsonTranscoder, #decode(String)]
1854
2000
 
@@ -1894,6 +2040,8 @@ module Couchbase
1894
2040
  # @param [Boolean, nil] flex_index Tells the query engine to use a flex index (utilizing the search service)
1895
2041
  # @param [Boolean, nil] preserve_expiry Tells the query engine to preserve expiration values set on any documents
1896
2042
  # modified by this query.
2043
+ # @param [Boolean, nil] use_replica Specifies that the query engine should use replica nodes for KV fetches if
2044
+ # the active node is down. If not provided, the server default will be used
1897
2045
  # @param [String, nil] scope_qualifier Associate scope qualifier (also known as +query_context+) with the query.
1898
2046
  # The qualifier must be in form +{bucket_name}.{scope_name}+ or +default:{bucket_name}.{scope_name}+.
1899
2047
  # @param [JsonTranscoder] transcoder to decode rows
@@ -1925,6 +2073,7 @@ module Couchbase
1925
2073
  profile: :off,
1926
2074
  flex_index: nil,
1927
2075
  preserve_expiry: nil,
2076
+ use_replica: nil,
1928
2077
  scope_qualifier: nil,
1929
2078
  scan_consistency: :not_bounded,
1930
2079
  mutation_state: nil,
@@ -1950,6 +2099,7 @@ module Couchbase
1950
2099
  @profile = profile
1951
2100
  @flex_index = flex_index
1952
2101
  @preserve_expiry = preserve_expiry
2102
+ @use_replica = use_replica
1953
2103
  @scope_qualifier = scope_qualifier
1954
2104
  @scan_consistency = scan_consistency
1955
2105
  @mutation_state = mutation_state
@@ -2043,6 +2193,7 @@ module Couchbase
2043
2193
  readonly: @readonly,
2044
2194
  flex_index: @flex_index,
2045
2195
  preserve_expiry: @preserve_expiry,
2196
+ use_replica: @use_replica,
2046
2197
  scan_wait: Utils::Time.extract_duration(@scan_wait),
2047
2198
  scan_cap: @scan_cap,
2048
2199
  pipeline_batch: @pipeline_batch,
@@ -79,7 +79,7 @@ module Couchbase
79
79
  metrics.warning_count = resp[:meta][:metrics][:warning_count]
80
80
  end
81
81
  end
82
- res[:warnings] = resp[:warnings].map { |warn| Cluster::QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
82
+ meta.warnings = resp[:warnings].map { |warn| Cluster::QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
83
83
  end
84
84
  res.instance_variable_set(:@rows, resp[:rows])
85
85
  end
@@ -48,8 +48,21 @@ module Couchbase
48
48
  end
49
49
  end
50
50
 
51
+ # This method converts its argument to milliseconds
52
+ #
53
+ # 1. Integer values are interpreted as a number of milliseconds
54
+ # 2. If the argument is a Duration-like object and responds to #in_milliseconds,
55
+ # then use it and convert result to Integer
56
+ # 3. Otherwise invoke #to_i on the argument and interpret it as a number of milliseconds
51
57
  def extract_duration(number_or_duration)
52
- number_or_duration.respond_to?(:in_milliseconds) ? number_or_duration.public_send(:in_milliseconds) : number_or_duration
58
+ return unless number_or_duration
59
+ return number_or_duration if number_or_duration.class == Integer # rubocop:disable Style/ClassEqualityComparison avoid overrides of #is_a?, #kind_of?
60
+
61
+ if number_or_duration.respond_to?(:in_milliseconds)
62
+ number_or_duration.public_send(:in_milliseconds)
63
+ else
64
+ number_or_duration
65
+ end.to_i
53
66
  end
54
67
  end
55
68
  end
@@ -19,5 +19,5 @@ module Couchbase
19
19
  # $ ruby -rcouchbase -e 'pp Couchbase::VERSION'
20
20
  # {:sdk=>"3.4.0", :ruby_abi=>"3.1.0", :revision=>"416fe68e6029ec8a4c40611cf6e6b30d3b90d20f"}
21
21
  VERSION = {} unless defined?(VERSION) # rubocop:disable Style/MutableConstant
22
- VERSION.update(:sdk => "3.4.3".freeze)
22
+ VERSION.update(:sdk => "3.4.4".freeze)
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.3
4
+ version: 3.4.4
5
5
  platform: arm64-darwin-20
6
6
  authors:
7
7
  - Sergey Avseyev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-17 00:00:00.000000000 Z
11
+ date: 2023-08-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Modern SDK for Couchbase Server
14
14
  email:
@@ -41,6 +41,7 @@ files:
41
41
  - lib/couchbase/diagnostics.rb
42
42
  - lib/couchbase/errors.rb
43
43
  - lib/couchbase/json_transcoder.rb
44
+ - lib/couchbase/key_value_scan.rb
44
45
  - lib/couchbase/libcouchbase.bundle
45
46
  - lib/couchbase/logger.rb
46
47
  - lib/couchbase/management.rb
@@ -77,9 +78,9 @@ metadata:
77
78
  homepage_uri: https://docs.couchbase.com/ruby-sdk/current/hello-world/start-using-sdk.html
78
79
  bug_tracker_uri: https://couchbase.com/issues/browse/RCBC
79
80
  mailing_list_uri: https://forums.couchbase.com/c/ruby-sdk
80
- source_code_uri: https://github.com/couchbase/couchbase-ruby-client/tree/3.4.3
81
- changelog_uri: https://github.com/couchbase/couchbase-ruby-client/releases/tag/3.4.3
82
- documentation_uri: https://docs.couchbase.com/sdk-api/couchbase-ruby-client-3.4.3/index.html
81
+ source_code_uri: https://github.com/couchbase/couchbase-ruby-client/tree/3.4.4
82
+ changelog_uri: https://github.com/couchbase/couchbase-ruby-client/releases/tag/3.4.4
83
+ documentation_uri: https://docs.couchbase.com/sdk-api/couchbase-ruby-client-3.4.4/index.html
83
84
  github_repo: ssh://github.com/couchbase/couchbase-ruby-client
84
85
  rubygems_mfa_required: 'true'
85
86
  post_install_message: