couchbase 3.4.3 → 3.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/ext/couchbase/CMakeLists.txt +15 -1
- data/ext/couchbase/core/bucket.cxx +183 -152
- data/ext/couchbase/core/bucket.hxx +17 -4
- data/ext/couchbase/core/cluster.hxx +34 -13
- data/ext/couchbase/core/cluster_options.hxx +3 -0
- data/ext/couchbase/core/crud_component.cxx +51 -22
- data/ext/couchbase/core/error_context/key_value.cxx +2 -1
- data/ext/couchbase/core/error_context/key_value.hxx +10 -12
- data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
- data/ext/couchbase/core/impl/cluster.cxx +6 -0
- data/ext/couchbase/core/impl/create_bucket.cxx +155 -0
- data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
- data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
- data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
- data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
- data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
- data/ext/couchbase/core/impl/get_all_buckets.cxx +163 -0
- data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
- data/ext/couchbase/core/impl/get_bucket.cxx +153 -0
- data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
- data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
- data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
- data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
- data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
- data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +176 -0
- data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
- data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +167 -0
- data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
- data/ext/couchbase/core/impl/lookup_in_replica.cxx +97 -0
- data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
- data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
- data/ext/couchbase/core/impl/query.cxx +1 -0
- data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
- data/ext/couchbase/core/impl/update_bucket.cxx +130 -0
- data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
- data/ext/couchbase/core/io/dns_client.cxx +111 -40
- data/ext/couchbase/core/io/dns_config.cxx +5 -4
- data/ext/couchbase/core/io/http_session.hxx +24 -1
- data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
- data/ext/couchbase/core/io/mcbp_session.cxx +80 -43
- data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
- data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
- data/ext/couchbase/core/logger/logger.cxx +80 -20
- data/ext/couchbase/core/logger/logger.hxx +31 -0
- data/ext/couchbase/core/meta/features.hxx +25 -0
- data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
- data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
- data/ext/couchbase/core/operations/document_query.cxx +11 -0
- data/ext/couchbase/core/operations/document_query.hxx +1 -0
- data/ext/couchbase/core/operations.hxx +2 -0
- data/ext/couchbase/core/origin.cxx +270 -0
- data/ext/couchbase/core/origin.hxx +2 -0
- data/ext/couchbase/core/protocol/client_response.hxx +1 -0
- data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
- data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
- data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
- data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
- data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
- data/ext/couchbase/core/protocol/status.cxx +2 -2
- data/ext/couchbase/core/range_scan_options.cxx +3 -27
- data/ext/couchbase/core/range_scan_options.hxx +13 -17
- data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
- data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
- data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
- data/ext/couchbase/core/scan_options.hxx +0 -19
- data/ext/couchbase/core/scan_result.cxx +19 -5
- data/ext/couchbase/core/scan_result.hxx +5 -2
- data/ext/couchbase/core/timeout_defaults.hxx +2 -3
- data/ext/couchbase/core/topology/capabilities.hxx +3 -0
- data/ext/couchbase/core/topology/capabilities_fmt.hxx +8 -0
- data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
- data/ext/couchbase/core/topology/configuration.hxx +15 -0
- data/ext/couchbase/core/topology/configuration_json.hxx +6 -1
- data/ext/couchbase/core/utils/connection_string.cxx +62 -47
- data/ext/couchbase/core/utils/connection_string.hxx +1 -0
- data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
- data/ext/couchbase/couchbase/behavior_options.hxx +19 -2
- data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
- data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
- data/ext/couchbase/couchbase/cluster.hxx +14 -0
- data/ext/couchbase/couchbase/collection.hxx +111 -0
- data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
- data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
- data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
- data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
- data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
- data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
- data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
- data/ext/couchbase/couchbase/error_codes.hxx +1 -2
- data/ext/couchbase/couchbase/error_context.hxx +10 -2
- data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
- data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
- data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
- data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
- data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
- data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
- data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
- data/ext/couchbase/couchbase/get_options.hxx +2 -2
- data/ext/couchbase/couchbase/insert_options.hxx +3 -3
- data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
- data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
- data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
- data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
- data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
- data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
- data/ext/couchbase/couchbase/management/bucket_settings.hxx +116 -0
- data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
- data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
- data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
- data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
- data/ext/couchbase/couchbase/query_options.hxx +18 -0
- data/ext/couchbase/couchbase/remove_options.hxx +2 -2
- data/ext/couchbase/couchbase/replace_options.hxx +3 -3
- data/ext/couchbase/couchbase/security_options.hxx +15 -0
- data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
- data/ext/couchbase/couchbase/touch_options.hxx +2 -2
- data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
- data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
- data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
- data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
- data/ext/couchbase/test/CMakeLists.txt +1 -0
- data/ext/couchbase/test/test_integration_collections.cxx +6 -0
- data/ext/couchbase/test/test_integration_crud.cxx +5 -0
- data/ext/couchbase/test/test_integration_examples.cxx +137 -1
- data/ext/couchbase/test/test_integration_management.cxx +709 -266
- data/ext/couchbase/test/test_integration_query.cxx +19 -7
- data/ext/couchbase/test/test_integration_range_scan.cxx +351 -112
- data/ext/couchbase/test/test_integration_search.cxx +10 -1
- data/ext/couchbase/test/test_integration_subdoc.cxx +655 -0
- data/ext/couchbase/test/test_transaction_public_async_api.cxx +13 -12
- data/ext/couchbase/test/test_transaction_public_blocking_api.cxx +27 -21
- data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
- data/ext/couchbase/test/test_unit_query.cxx +75 -0
- data/ext/couchbase.cxx +583 -29
- data/ext/revisions.rb +3 -3
- data/lib/couchbase/cluster.rb +1 -1
- data/lib/couchbase/collection.rb +108 -0
- data/lib/couchbase/collection_options.rb +100 -0
- data/lib/couchbase/errors.rb +5 -0
- data/lib/couchbase/key_value_scan.rb +125 -0
- data/lib/couchbase/options.rb +151 -0
- data/lib/couchbase/scope.rb +1 -1
- data/lib/couchbase/utils/time.rb +14 -1
- data/lib/couchbase/version.rb +1 -1
- metadata +41 -7
- data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
data/ext/revisions.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
cmake_flags << "-DEXT_GIT_REVISION=
|
2
|
-
cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_REVISION=
|
3
|
-
cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_DESCRIBE=1.0.0-dp.
|
1
|
+
cmake_flags << "-DEXT_GIT_REVISION=167d2e58559c91239675f1e7f7ffa2f6176f0512"
|
2
|
+
cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_REVISION=43cf66a592d1f8112141a73e5a563d7187ee0ee6"
|
3
|
+
cmake_flags << "-DCOUCHBASE_CXX_CLIENT_GIT_DESCRIBE=1.0.0-dp.8-0-g43cf66a"
|
data/lib/couchbase/cluster.rb
CHANGED
@@ -124,7 +124,7 @@ module Couchbase
|
|
124
124
|
metrics.warning_count = resp[:meta][:metrics][:warning_count]
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
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
|
data/lib/couchbase/collection.rb
CHANGED
@@ -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
|
data/lib/couchbase/errors.rb
CHANGED
@@ -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
|
data/lib/couchbase/options.rb
CHANGED
@@ -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,
|
data/lib/couchbase/scope.rb
CHANGED
@@ -79,7 +79,7 @@ module Couchbase
|
|
79
79
|
metrics.warning_count = resp[:meta][:metrics][:warning_count]
|
80
80
|
end
|
81
81
|
end
|
82
|
-
|
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
|
data/lib/couchbase/utils/time.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/couchbase/version.rb
CHANGED
@@ -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.
|
22
|
+
VERSION.update(:sdk => "3.4.4".freeze)
|
23
23
|
end
|