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/couchbase.cxx
CHANGED
@@ -33,9 +33,12 @@
|
|
33
33
|
#include <core/platform/terminate_handler.h>
|
34
34
|
|
35
35
|
#include <core/cluster.hxx>
|
36
|
+
|
37
|
+
#include <core/agent_group.hxx>
|
36
38
|
#include <core/design_document_namespace_fmt.hxx>
|
37
39
|
#include <core/logger/configuration.hxx>
|
38
40
|
#include <core/operations.hxx>
|
41
|
+
|
39
42
|
#include <core/operations/management/analytics.hxx>
|
40
43
|
#include <core/operations/management/bucket.hxx>
|
41
44
|
#include <core/operations/management/cluster_developer_preview_enable.hxx>
|
@@ -45,6 +48,12 @@
|
|
45
48
|
#include <core/operations/management/user.hxx>
|
46
49
|
#include <core/operations/management/view.hxx>
|
47
50
|
|
51
|
+
#include <core/impl/subdoc/path_flags.hxx>
|
52
|
+
|
53
|
+
#include <core/range_scan_options.hxx>
|
54
|
+
#include <core/range_scan_orchestrator.hxx>
|
55
|
+
#include <core/range_scan_orchestrator_options.hxx>
|
56
|
+
|
48
57
|
#include <core/io/dns_client.hxx>
|
49
58
|
#include <core/io/dns_config.hxx>
|
50
59
|
#include <core/utils/connection_string.hxx>
|
@@ -435,7 +444,7 @@ cb_backend_close(cb_backend_data* backend)
|
|
435
444
|
static void
|
436
445
|
cb_Backend_mark(void* /* ptr */)
|
437
446
|
{
|
438
|
-
/* no
|
447
|
+
/* no embedded ruby objects -- no mark */
|
439
448
|
}
|
440
449
|
|
441
450
|
static void
|
@@ -495,6 +504,8 @@ cb_backend_to_cluster(VALUE self)
|
|
495
504
|
return backend->cluster;
|
496
505
|
}
|
497
506
|
|
507
|
+
static VALUE eCouchbaseError;
|
508
|
+
|
498
509
|
static VALUE eAmbiguousTimeout;
|
499
510
|
static VALUE eAuthenticationFailure;
|
500
511
|
static VALUE eBucketExists;
|
@@ -534,6 +545,7 @@ static VALUE eInvalidArgument;
|
|
534
545
|
static VALUE eJobQueueFull;
|
535
546
|
static VALUE eLinkNotFound;
|
536
547
|
static VALUE eLinkExists;
|
548
|
+
static VALUE eMutationTokenOutdated;
|
537
549
|
static VALUE eNumberTooBig;
|
538
550
|
static VALUE eParsingFailure;
|
539
551
|
static VALUE ePathExists;
|
@@ -586,7 +598,7 @@ static void
|
|
586
598
|
init_exceptions(VALUE mCouchbase)
|
587
599
|
{
|
588
600
|
VALUE mError = rb_define_module_under(mCouchbase, "Error");
|
589
|
-
|
601
|
+
eCouchbaseError = rb_define_class_under(mError, "CouchbaseError", rb_eStandardError);
|
590
602
|
|
591
603
|
VALUE eTimeout = rb_define_class_under(mError, "Timeout", eCouchbaseError);
|
592
604
|
|
@@ -629,6 +641,7 @@ init_exceptions(VALUE mCouchbase)
|
|
629
641
|
eJobQueueFull = rb_define_class_under(mError, "JobQueueFull", eCouchbaseError);
|
630
642
|
eLinkNotFound = rb_define_class_under(mError, "LinkNotFound", eCouchbaseError);
|
631
643
|
eLinkExists = rb_define_class_under(mError, "LinkExists", eCouchbaseError);
|
644
|
+
eMutationTokenOutdated = rb_define_class_under(mError, "MutationTokenOutdated", eCouchbaseError);
|
632
645
|
eNumberTooBig = rb_define_class_under(mError, "NumberTooBig", eCouchbaseError);
|
633
646
|
eParsingFailure = rb_define_class_under(mError, "ParsingFailure", eCouchbaseError);
|
634
647
|
ePathExists = rb_define_class_under(mError, "PathExists", eCouchbaseError);
|
@@ -784,6 +797,9 @@ cb_map_error_code(std::error_code ec, const std::string& message, bool include_e
|
|
784
797
|
case couchbase::errc::key_value::durable_write_re_commit_in_progress:
|
785
798
|
return rb_exc_new_cstr(eDurableWriteReCommitInProgress, what.c_str());
|
786
799
|
|
800
|
+
case couchbase::errc::key_value::mutation_token_outdated:
|
801
|
+
return rb_exc_new_cstr(eMutationTokenOutdated, what.c_str());
|
802
|
+
|
787
803
|
case couchbase::errc::key_value::path_not_found:
|
788
804
|
return rb_exc_new_cstr(ePathNotFound, what.c_str());
|
789
805
|
|
@@ -834,6 +850,10 @@ cb_map_error_code(std::error_code ec, const std::string& message, bool include_e
|
|
834
850
|
|
835
851
|
case couchbase::errc::key_value::cannot_revive_living_document:
|
836
852
|
return rb_exc_new_cstr(eCannotReviveLivingDocument, what.c_str());
|
853
|
+
|
854
|
+
case couchbase::errc::key_value::range_scan_completed:
|
855
|
+
// Should not be exposed to the Ruby SDK, map it to a BackendError
|
856
|
+
return rb_exc_new_cstr(eBackendError, what.c_str());
|
837
857
|
}
|
838
858
|
} else if (ec.category() == couchbase::core::impl::query_category()) {
|
839
859
|
switch (static_cast<couchbase::errc::query>(ec.value())) {
|
@@ -3409,7 +3429,7 @@ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3409
3429
|
static VALUE
|
3410
3430
|
cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
|
3411
3431
|
{
|
3412
|
-
const auto&
|
3432
|
+
const auto& cluster = cb_backend_to_cluster(self);
|
3413
3433
|
|
3414
3434
|
Check_Type(bucket, T_STRING);
|
3415
3435
|
Check_Type(scope, T_STRING);
|
@@ -3425,10 +3445,6 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3425
3445
|
}
|
3426
3446
|
|
3427
3447
|
try {
|
3428
|
-
couchbase::lookup_in_options opts;
|
3429
|
-
couchbase::ruby::set_timeout(opts, options);
|
3430
|
-
couchbase::ruby::set_access_deleted(opts, options);
|
3431
|
-
|
3432
3448
|
couchbase::core::document_id doc_id{
|
3433
3449
|
cb_string_new(bucket),
|
3434
3450
|
cb_string_new(scope),
|
@@ -3436,12 +3452,15 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3436
3452
|
cb_string_new(id),
|
3437
3453
|
};
|
3438
3454
|
|
3455
|
+
couchbase::core::operations::lookup_in_request req{ doc_id };
|
3456
|
+
cb_extract_timeout(req, options);
|
3457
|
+
cb_extract_option_bool(req.access_deleted, options, "access_deleted");
|
3458
|
+
|
3439
3459
|
static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
|
3440
3460
|
static VALUE path_property = rb_id2sym(rb_intern("path"));
|
3441
3461
|
static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
|
3442
3462
|
|
3443
3463
|
auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
|
3444
|
-
couchbase::lookup_in_specs cxx_specs;
|
3445
3464
|
for (std::size_t i = 0; i < entries_size; ++i) {
|
3446
3465
|
VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
|
3447
3466
|
cb_check_type(entry, T_HASH);
|
@@ -3450,29 +3469,138 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3450
3469
|
bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
|
3451
3470
|
VALUE path = rb_hash_aref(entry, path_property);
|
3452
3471
|
cb_check_type(path, T_STRING);
|
3472
|
+
auto opcode = couchbase::core::impl::subdoc::opcode{};
|
3453
3473
|
if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
|
3454
|
-
|
3474
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_doc;
|
3455
3475
|
} else if (operation_id == rb_intern("get")) {
|
3456
|
-
|
3476
|
+
opcode = couchbase::core::impl::subdoc::opcode::get;
|
3457
3477
|
} else if (operation_id == rb_intern("exists")) {
|
3458
|
-
|
3478
|
+
opcode = couchbase::core::impl::subdoc::opcode::exists;
|
3459
3479
|
} else if (operation_id == rb_intern("count")) {
|
3460
|
-
|
3480
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_count;
|
3461
3481
|
} else {
|
3462
3482
|
throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
|
3463
3483
|
}
|
3464
3484
|
cb_check_type(path, T_STRING);
|
3485
|
+
|
3486
|
+
req.specs.emplace_back(couchbase::core::impl::subdoc::command{
|
3487
|
+
opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
|
3465
3488
|
}
|
3466
3489
|
|
3467
|
-
auto
|
3468
|
-
|
3469
|
-
|
3470
|
-
|
3471
|
-
|
3490
|
+
auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_response>>();
|
3491
|
+
auto f = barrier->get_future();
|
3492
|
+
cluster->execute(req, [barrier](couchbase::core::operations::lookup_in_response&& resp) { barrier->set_value(std::move(resp)); });
|
3493
|
+
auto resp = cb_wait_for_future(f);
|
3494
|
+
if (resp.ctx.ec()) {
|
3495
|
+
cb_throw_error_code(resp.ctx, "unable to perform lookup_in operation");
|
3496
|
+
}
|
3472
3497
|
|
3473
|
-
|
3474
|
-
|
3475
|
-
|
3498
|
+
static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
|
3499
|
+
static VALUE fields_property = rb_id2sym(rb_intern("fields"));
|
3500
|
+
static VALUE index_property = rb_id2sym(rb_intern("index"));
|
3501
|
+
static VALUE exists_property = rb_id2sym(rb_intern("exists"));
|
3502
|
+
static VALUE cas_property = rb_id2sym(rb_intern("cas"));
|
3503
|
+
static VALUE value_property = rb_id2sym(rb_intern("value"));
|
3504
|
+
static VALUE error_property = rb_id2sym(rb_intern("error"));
|
3505
|
+
|
3506
|
+
VALUE res = rb_hash_new();
|
3507
|
+
rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas));
|
3508
|
+
VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
|
3509
|
+
rb_hash_aset(res, fields_property, fields);
|
3510
|
+
rb_hash_aset(res, deleted_property, resp.deleted ? Qtrue : Qfalse);
|
3511
|
+
for (std::size_t i = 0; i < entries_size; ++i) {
|
3512
|
+
auto resp_entry = resp.fields.at(i);
|
3513
|
+
VALUE entry = rb_hash_new();
|
3514
|
+
rb_hash_aset(entry, index_property, ULL2NUM(resp_entry.original_index));
|
3515
|
+
rb_hash_aset(entry, exists_property, resp_entry.exists ? Qtrue : Qfalse);
|
3516
|
+
rb_hash_aset(entry, path_property, cb_str_new(resp_entry.path));
|
3517
|
+
if (!resp_entry.value.empty()) {
|
3518
|
+
rb_hash_aset(entry, value_property, cb_str_new(resp_entry.value));
|
3519
|
+
}
|
3520
|
+
if (resp_entry.ec && resp_entry.ec != couchbase::errc::key_value::path_not_found) {
|
3521
|
+
rb_hash_aset(entry,
|
3522
|
+
error_property,
|
3523
|
+
cb_map_error_code(resp_entry.ec,
|
3524
|
+
fmt::format("error getting result for spec at index {}, path \"{}\"", i, resp_entry.path)));
|
3525
|
+
}
|
3526
|
+
rb_ary_store(fields, static_cast<long>(i), entry);
|
3527
|
+
}
|
3528
|
+
return res;
|
3529
|
+
} catch (const std::system_error& se) {
|
3530
|
+
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
|
3531
|
+
} catch (const ruby_exception& e) {
|
3532
|
+
rb_exc_raise(e.exception_object());
|
3533
|
+
}
|
3534
|
+
return Qnil;
|
3535
|
+
}
|
3536
|
+
|
3537
|
+
static VALUE
|
3538
|
+
cb_Backend_document_lookup_in_any_replica(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
|
3539
|
+
{
|
3540
|
+
const auto& cluster = cb_backend_to_cluster(self);
|
3541
|
+
|
3542
|
+
Check_Type(bucket, T_STRING);
|
3543
|
+
Check_Type(scope, T_STRING);
|
3544
|
+
Check_Type(collection, T_STRING);
|
3545
|
+
Check_Type(id, T_STRING);
|
3546
|
+
Check_Type(specs, T_ARRAY);
|
3547
|
+
if (RARRAY_LEN(specs) <= 0) {
|
3548
|
+
rb_raise(rb_eArgError, "Array with specs cannot be empty");
|
3549
|
+
return Qnil;
|
3550
|
+
}
|
3551
|
+
if (!NIL_P(options)) {
|
3552
|
+
Check_Type(options, T_HASH);
|
3553
|
+
}
|
3554
|
+
|
3555
|
+
try {
|
3556
|
+
couchbase::core::document_id doc_id{
|
3557
|
+
cb_string_new(bucket),
|
3558
|
+
cb_string_new(scope),
|
3559
|
+
cb_string_new(collection),
|
3560
|
+
cb_string_new(id),
|
3561
|
+
};
|
3562
|
+
|
3563
|
+
couchbase::core::operations::lookup_in_any_replica_request req{ doc_id };
|
3564
|
+
cb_extract_timeout(req, options);
|
3565
|
+
|
3566
|
+
static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
|
3567
|
+
static VALUE path_property = rb_id2sym(rb_intern("path"));
|
3568
|
+
static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
|
3569
|
+
|
3570
|
+
auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
|
3571
|
+
for (std::size_t i = 0; i < entries_size; ++i) {
|
3572
|
+
VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
|
3573
|
+
cb_check_type(entry, T_HASH);
|
3574
|
+
VALUE operation = rb_hash_aref(entry, opcode_property);
|
3575
|
+
cb_check_type(operation, T_SYMBOL);
|
3576
|
+
bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
|
3577
|
+
VALUE path = rb_hash_aref(entry, path_property);
|
3578
|
+
cb_check_type(path, T_STRING);
|
3579
|
+
auto opcode = couchbase::core::impl::subdoc::opcode{};
|
3580
|
+
if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
|
3581
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_doc;
|
3582
|
+
} else if (operation_id == rb_intern("get")) {
|
3583
|
+
opcode = couchbase::core::impl::subdoc::opcode::get;
|
3584
|
+
} else if (operation_id == rb_intern("exists")) {
|
3585
|
+
opcode = couchbase::core::impl::subdoc::opcode::exists;
|
3586
|
+
} else if (operation_id == rb_intern("count")) {
|
3587
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_count;
|
3588
|
+
} else {
|
3589
|
+
throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
|
3590
|
+
}
|
3591
|
+
cb_check_type(path, T_STRING);
|
3592
|
+
|
3593
|
+
req.specs.emplace_back(couchbase::core::impl::subdoc::command{
|
3594
|
+
opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
|
3595
|
+
}
|
3596
|
+
|
3597
|
+
auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_any_replica_response>>();
|
3598
|
+
auto f = barrier->get_future();
|
3599
|
+
cluster->execute(
|
3600
|
+
req, [barrier](couchbase::core::operations::lookup_in_any_replica_response&& resp) { barrier->set_value(std::move(resp)); });
|
3601
|
+
auto resp = cb_wait_for_future(f);
|
3602
|
+
if (resp.ctx.ec()) {
|
3603
|
+
cb_throw_error_code(resp.ctx, "unable to perform lookup_in_any_replica operation");
|
3476
3604
|
}
|
3477
3605
|
|
3478
3606
|
static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
|
@@ -3481,23 +3609,153 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3481
3609
|
static VALUE exists_property = rb_id2sym(rb_intern("exists"));
|
3482
3610
|
static VALUE cas_property = rb_id2sym(rb_intern("cas"));
|
3483
3611
|
static VALUE value_property = rb_id2sym(rb_intern("value"));
|
3612
|
+
static VALUE error_property = rb_id2sym(rb_intern("error"));
|
3613
|
+
static VALUE is_replica_property = rb_id2sym(rb_intern("is_replica"));
|
3484
3614
|
|
3485
3615
|
VALUE res = rb_hash_new();
|
3486
|
-
rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas
|
3616
|
+
rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas));
|
3487
3617
|
VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
|
3488
3618
|
rb_hash_aset(res, fields_property, fields);
|
3489
|
-
rb_hash_aset(res, deleted_property, resp.
|
3619
|
+
rb_hash_aset(res, deleted_property, resp.deleted ? Qtrue : Qfalse);
|
3620
|
+
rb_hash_aset(res, is_replica_property, resp.is_replica ? Qtrue : Qfalse);
|
3621
|
+
|
3490
3622
|
for (std::size_t i = 0; i < entries_size; ++i) {
|
3623
|
+
auto resp_entry = resp.fields.at(i);
|
3491
3624
|
VALUE entry = rb_hash_new();
|
3492
|
-
rb_hash_aset(entry, index_property, ULL2NUM(
|
3493
|
-
rb_hash_aset(entry, exists_property,
|
3494
|
-
rb_hash_aset(entry, path_property,
|
3495
|
-
if (
|
3496
|
-
|
3497
|
-
|
3625
|
+
rb_hash_aset(entry, index_property, ULL2NUM(resp_entry.original_index));
|
3626
|
+
rb_hash_aset(entry, exists_property, resp_entry.exists ? Qtrue : Qfalse);
|
3627
|
+
rb_hash_aset(entry, path_property, cb_str_new(resp_entry.path));
|
3628
|
+
if (!resp_entry.value.empty()) {
|
3629
|
+
rb_hash_aset(entry, value_property, cb_str_new(resp_entry.value));
|
3630
|
+
}
|
3631
|
+
if (resp_entry.ec && resp_entry.ec != couchbase::errc::key_value::path_not_found) {
|
3632
|
+
rb_hash_aset(entry,
|
3633
|
+
error_property,
|
3634
|
+
cb_map_error_code(resp_entry.ec,
|
3635
|
+
fmt::format("error getting result for spec at index {}, path \"{}\"", i, resp_entry.path)));
|
3498
3636
|
}
|
3499
3637
|
rb_ary_store(fields, static_cast<long>(i), entry);
|
3500
3638
|
}
|
3639
|
+
|
3640
|
+
return res;
|
3641
|
+
} catch (const std::system_error& se) {
|
3642
|
+
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
|
3643
|
+
} catch (const ruby_exception& e) {
|
3644
|
+
rb_exc_raise(e.exception_object());
|
3645
|
+
}
|
3646
|
+
return Qnil;
|
3647
|
+
}
|
3648
|
+
|
3649
|
+
static VALUE
|
3650
|
+
cb_Backend_document_lookup_in_all_replicas(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
|
3651
|
+
{
|
3652
|
+
const auto& cluster = cb_backend_to_cluster(self);
|
3653
|
+
|
3654
|
+
Check_Type(bucket, T_STRING);
|
3655
|
+
Check_Type(scope, T_STRING);
|
3656
|
+
Check_Type(collection, T_STRING);
|
3657
|
+
Check_Type(id, T_STRING);
|
3658
|
+
Check_Type(specs, T_ARRAY);
|
3659
|
+
if (RARRAY_LEN(specs) <= 0) {
|
3660
|
+
rb_raise(rb_eArgError, "Array with specs cannot be empty");
|
3661
|
+
return Qnil;
|
3662
|
+
}
|
3663
|
+
if (!NIL_P(options)) {
|
3664
|
+
Check_Type(options, T_HASH);
|
3665
|
+
}
|
3666
|
+
|
3667
|
+
try {
|
3668
|
+
couchbase::core::document_id doc_id{
|
3669
|
+
cb_string_new(bucket),
|
3670
|
+
cb_string_new(scope),
|
3671
|
+
cb_string_new(collection),
|
3672
|
+
cb_string_new(id),
|
3673
|
+
};
|
3674
|
+
|
3675
|
+
couchbase::core::operations::lookup_in_all_replicas_request req{ doc_id };
|
3676
|
+
cb_extract_timeout(req, options);
|
3677
|
+
|
3678
|
+
static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
|
3679
|
+
static VALUE path_property = rb_id2sym(rb_intern("path"));
|
3680
|
+
static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
|
3681
|
+
|
3682
|
+
auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
|
3683
|
+
for (std::size_t i = 0; i < entries_size; ++i) {
|
3684
|
+
VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
|
3685
|
+
cb_check_type(entry, T_HASH);
|
3686
|
+
VALUE operation = rb_hash_aref(entry, opcode_property);
|
3687
|
+
cb_check_type(operation, T_SYMBOL);
|
3688
|
+
bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
|
3689
|
+
VALUE path = rb_hash_aref(entry, path_property);
|
3690
|
+
cb_check_type(path, T_STRING);
|
3691
|
+
auto opcode = couchbase::core::impl::subdoc::opcode{};
|
3692
|
+
if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
|
3693
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_doc;
|
3694
|
+
} else if (operation_id == rb_intern("get")) {
|
3695
|
+
opcode = couchbase::core::impl::subdoc::opcode::get;
|
3696
|
+
} else if (operation_id == rb_intern("exists")) {
|
3697
|
+
opcode = couchbase::core::impl::subdoc::opcode::exists;
|
3698
|
+
} else if (operation_id == rb_intern("count")) {
|
3699
|
+
opcode = couchbase::core::impl::subdoc::opcode::get_count;
|
3700
|
+
} else {
|
3701
|
+
throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
|
3702
|
+
}
|
3703
|
+
cb_check_type(path, T_STRING);
|
3704
|
+
|
3705
|
+
req.specs.emplace_back(couchbase::core::impl::subdoc::command{
|
3706
|
+
opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
|
3707
|
+
}
|
3708
|
+
|
3709
|
+
auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_all_replicas_response>>();
|
3710
|
+
auto f = barrier->get_future();
|
3711
|
+
cluster->execute(
|
3712
|
+
req, [barrier](couchbase::core::operations::lookup_in_all_replicas_response&& resp) { barrier->set_value(std::move(resp)); });
|
3713
|
+
auto resp = cb_wait_for_future(f);
|
3714
|
+
if (resp.ctx.ec()) {
|
3715
|
+
cb_throw_error_code(resp.ctx, "unable to perform lookup_in_all_replicas operation");
|
3716
|
+
}
|
3717
|
+
|
3718
|
+
static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
|
3719
|
+
static VALUE fields_property = rb_id2sym(rb_intern("fields"));
|
3720
|
+
static VALUE index_property = rb_id2sym(rb_intern("index"));
|
3721
|
+
static VALUE exists_property = rb_id2sym(rb_intern("exists"));
|
3722
|
+
static VALUE cas_property = rb_id2sym(rb_intern("cas"));
|
3723
|
+
static VALUE value_property = rb_id2sym(rb_intern("value"));
|
3724
|
+
static VALUE error_property = rb_id2sym(rb_intern("error"));
|
3725
|
+
static VALUE is_replica_property = rb_id2sym(rb_intern("is_replica"));
|
3726
|
+
|
3727
|
+
auto lookup_in_entries_size = resp.entries.size();
|
3728
|
+
VALUE res = rb_ary_new_capa(static_cast<long>(lookup_in_entries_size));
|
3729
|
+
for (std::size_t j = 0; j < lookup_in_entries_size; ++j) {
|
3730
|
+
auto lookup_in_entry = resp.entries.at(j);
|
3731
|
+
VALUE lookup_in_entry_res = rb_hash_new();
|
3732
|
+
rb_hash_aset(lookup_in_entry_res, cas_property, cb_cas_to_num(lookup_in_entry.cas));
|
3733
|
+
VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
|
3734
|
+
rb_hash_aset(lookup_in_entry_res, fields_property, fields);
|
3735
|
+
rb_hash_aset(lookup_in_entry_res, deleted_property, lookup_in_entry.deleted ? Qtrue : Qfalse);
|
3736
|
+
rb_hash_aset(lookup_in_entry_res, is_replica_property, lookup_in_entry.is_replica ? Qtrue : Qfalse);
|
3737
|
+
|
3738
|
+
for (std::size_t i = 0; i < entries_size; ++i) {
|
3739
|
+
auto field_entry = lookup_in_entry.fields.at(i);
|
3740
|
+
VALUE entry = rb_hash_new();
|
3741
|
+
rb_hash_aset(entry, index_property, ULL2NUM(field_entry.original_index));
|
3742
|
+
rb_hash_aset(entry, exists_property, field_entry.exists ? Qtrue : Qfalse);
|
3743
|
+
rb_hash_aset(entry, path_property, cb_str_new(field_entry.path));
|
3744
|
+
if (!field_entry.value.empty()) {
|
3745
|
+
rb_hash_aset(entry, value_property, cb_str_new(field_entry.value));
|
3746
|
+
}
|
3747
|
+
if (field_entry.ec && field_entry.ec != couchbase::errc::key_value::path_not_found) {
|
3748
|
+
rb_hash_aset(
|
3749
|
+
entry,
|
3750
|
+
error_property,
|
3751
|
+
cb_map_error_code(field_entry.ec,
|
3752
|
+
fmt::format("error getting result for spec at index {}, path \"{}\"", i, field_entry.path)));
|
3753
|
+
}
|
3754
|
+
rb_ary_store(fields, static_cast<long>(i), entry);
|
3755
|
+
}
|
3756
|
+
rb_ary_store(res, static_cast<long>(j), lookup_in_entry_res);
|
3757
|
+
}
|
3758
|
+
|
3501
3759
|
return res;
|
3502
3760
|
} catch (const std::system_error& se) {
|
3503
3761
|
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
|
@@ -3661,6 +3919,284 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
|
|
3661
3919
|
return Qnil;
|
3662
3920
|
}
|
3663
3921
|
|
3922
|
+
struct cb_core_scan_result_data {
|
3923
|
+
std::unique_ptr<couchbase::core::scan_result> scan_result{};
|
3924
|
+
};
|
3925
|
+
|
3926
|
+
static void
|
3927
|
+
cb_CoreScanResult_mark(void* ptr)
|
3928
|
+
{
|
3929
|
+
/* No embedded Ruby objects */
|
3930
|
+
}
|
3931
|
+
|
3932
|
+
static void
|
3933
|
+
cb_CoreScanResult_free(void* ptr)
|
3934
|
+
{
|
3935
|
+
auto* data = static_cast<cb_core_scan_result_data*>(ptr);
|
3936
|
+
if (data->scan_result != nullptr && !data->scan_result->is_cancelled()) {
|
3937
|
+
data->scan_result->cancel();
|
3938
|
+
}
|
3939
|
+
data->scan_result.reset();
|
3940
|
+
ruby_xfree(data);
|
3941
|
+
}
|
3942
|
+
|
3943
|
+
static const rb_data_type_t cb_core_scan_result_type {
|
3944
|
+
.wrap_struct_name = "Couchbase/Backend/CoreScanResult",
|
3945
|
+
.function = {
|
3946
|
+
.dmark = cb_CoreScanResult_mark,
|
3947
|
+
.dfree = cb_CoreScanResult_free,
|
3948
|
+
},
|
3949
|
+
.data = nullptr,
|
3950
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
3951
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
3952
|
+
#endif
|
3953
|
+
};
|
3954
|
+
|
3955
|
+
static VALUE
|
3956
|
+
cb_CoreScanResult_allocate(VALUE klass)
|
3957
|
+
{
|
3958
|
+
cb_core_scan_result_data* data = nullptr;
|
3959
|
+
VALUE obj = TypedData_Make_Struct(klass, cb_core_scan_result_data, &cb_core_scan_result_type, data);
|
3960
|
+
return obj;
|
3961
|
+
}
|
3962
|
+
|
3963
|
+
static VALUE
|
3964
|
+
cb_CoreScanResult_is_cancelled(VALUE self)
|
3965
|
+
{
|
3966
|
+
cb_core_scan_result_data* data = nullptr;
|
3967
|
+
TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
|
3968
|
+
auto resp = data->scan_result->is_cancelled();
|
3969
|
+
if (resp) {
|
3970
|
+
return Qtrue;
|
3971
|
+
} else {
|
3972
|
+
return Qfalse;
|
3973
|
+
}
|
3974
|
+
}
|
3975
|
+
|
3976
|
+
static VALUE
|
3977
|
+
cb_CoreScanResult_cancel(VALUE self)
|
3978
|
+
{
|
3979
|
+
cb_core_scan_result_data* data = nullptr;
|
3980
|
+
TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
|
3981
|
+
data->scan_result->cancel();
|
3982
|
+
return Qnil;
|
3983
|
+
}
|
3984
|
+
|
3985
|
+
static VALUE
|
3986
|
+
cb_CoreScanResult_next_item(VALUE self)
|
3987
|
+
{
|
3988
|
+
try {
|
3989
|
+
cb_core_scan_result_data* data = nullptr;
|
3990
|
+
TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
|
3991
|
+
auto barrier = std::make_shared<std::promise<tl::expected<couchbase::core::range_scan_item, std::error_code>>>();
|
3992
|
+
auto f = barrier->get_future();
|
3993
|
+
data->scan_result->next([barrier](couchbase::core::range_scan_item item, std::error_code ec) {
|
3994
|
+
if (ec) {
|
3995
|
+
return barrier->set_value(tl::unexpected(ec));
|
3996
|
+
} else {
|
3997
|
+
return barrier->set_value(item);
|
3998
|
+
}
|
3999
|
+
});
|
4000
|
+
auto resp = cb_wait_for_future(f);
|
4001
|
+
if (!resp.has_value()) {
|
4002
|
+
// If the error code is range_scan_completed return nil without raising an exception (nil signifies that there
|
4003
|
+
// are no more items)
|
4004
|
+
if (resp.error() != couchbase::errc::key_value::range_scan_completed) {
|
4005
|
+
cb_throw_error_code(resp.error(), "unable to fetch next scan item");
|
4006
|
+
}
|
4007
|
+
// Release ownership of scan_result unique pointer
|
4008
|
+
return Qnil;
|
4009
|
+
}
|
4010
|
+
auto item = resp.value();
|
4011
|
+
VALUE res = rb_hash_new();
|
4012
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("id")), cb_str_new(item.key));
|
4013
|
+
if (item.body.has_value()) {
|
4014
|
+
auto body = item.body.value();
|
4015
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("id")), cb_str_new(item.key));
|
4016
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("encoded")), cb_str_new(body.value));
|
4017
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("cas")), cb_cas_to_num(body.cas));
|
4018
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(body.flags));
|
4019
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("expiry")), UINT2NUM(body.expiry));
|
4020
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("id_only")), Qfalse);
|
4021
|
+
} else {
|
4022
|
+
rb_hash_aset(res, rb_id2sym(rb_intern("id_only")), Qtrue);
|
4023
|
+
}
|
4024
|
+
return res;
|
4025
|
+
} catch (const std::system_error& se) {
|
4026
|
+
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
|
4027
|
+
} catch (const ruby_exception& e) {
|
4028
|
+
rb_exc_raise(e.exception_object());
|
4029
|
+
}
|
4030
|
+
return Qnil;
|
4031
|
+
}
|
4032
|
+
|
4033
|
+
static VALUE
|
4034
|
+
cb_Backend_document_scan_create(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE scan_type, VALUE options)
|
4035
|
+
{
|
4036
|
+
const auto& cluster = cb_backend_to_cluster(self);
|
4037
|
+
|
4038
|
+
Check_Type(bucket, T_STRING);
|
4039
|
+
Check_Type(scope, T_STRING);
|
4040
|
+
Check_Type(collection, T_STRING);
|
4041
|
+
Check_Type(scan_type, T_HASH);
|
4042
|
+
if (!NIL_P(options)) {
|
4043
|
+
Check_Type(options, T_HASH);
|
4044
|
+
}
|
4045
|
+
|
4046
|
+
try {
|
4047
|
+
couchbase::core::range_scan_orchestrator_options orchestrator_options{};
|
4048
|
+
cb_extract_timeout(orchestrator_options, options);
|
4049
|
+
cb_extract_option_bool(orchestrator_options.ids_only, options, "ids_only");
|
4050
|
+
cb_extract_option_number(orchestrator_options.batch_item_limit, options, "batch_item_limit");
|
4051
|
+
cb_extract_option_number(orchestrator_options.batch_byte_limit, options, "batch_byte_limit");
|
4052
|
+
cb_extract_option_number(orchestrator_options.concurrency, options, "concurrency");
|
4053
|
+
|
4054
|
+
// Extracting the mutation state
|
4055
|
+
if (VALUE mutation_state = rb_hash_aref(options, rb_id2sym(rb_intern("mutation_state"))); !NIL_P(mutation_state)) {
|
4056
|
+
cb_check_type(mutation_state, T_ARRAY);
|
4057
|
+
auto state_size = static_cast<std::size_t>(RARRAY_LEN(mutation_state));
|
4058
|
+
|
4059
|
+
if (state_size > 0) {
|
4060
|
+
auto core_mut_state = couchbase::core::mutation_state{};
|
4061
|
+
core_mut_state.tokens.reserve(state_size);
|
4062
|
+
for (std::size_t i = 0; i < state_size; ++i) {
|
4063
|
+
VALUE token = rb_ary_entry(mutation_state, static_cast<long>(i));
|
4064
|
+
cb_check_type(token, T_HASH);
|
4065
|
+
VALUE bucket_name = rb_hash_aref(token, rb_id2sym(rb_intern("bucket_name")));
|
4066
|
+
cb_check_type(bucket_name, T_STRING);
|
4067
|
+
VALUE partition_id = rb_hash_aref(token, rb_id2sym(rb_intern("partition_id")));
|
4068
|
+
cb_check_type(partition_id, T_FIXNUM);
|
4069
|
+
VALUE partition_uuid = rb_hash_aref(token, rb_id2sym(rb_intern("partition_uuid")));
|
4070
|
+
switch (TYPE(partition_uuid)) {
|
4071
|
+
case T_FIXNUM:
|
4072
|
+
case T_BIGNUM:
|
4073
|
+
break;
|
4074
|
+
default:
|
4075
|
+
rb_raise(rb_eArgError, "partition_uuid must be an Integer");
|
4076
|
+
}
|
4077
|
+
VALUE sequence_number = rb_hash_aref(token, rb_id2sym(rb_intern("sequence_number")));
|
4078
|
+
switch (TYPE(sequence_number)) {
|
4079
|
+
case T_FIXNUM:
|
4080
|
+
case T_BIGNUM:
|
4081
|
+
break;
|
4082
|
+
default:
|
4083
|
+
rb_raise(rb_eArgError, "sequence_number must be an Integer");
|
4084
|
+
}
|
4085
|
+
core_mut_state.tokens.emplace_back(NUM2ULL(partition_uuid),
|
4086
|
+
NUM2ULL(sequence_number),
|
4087
|
+
gsl::narrow_cast<std::uint16_t>(NUM2UINT(partition_id)),
|
4088
|
+
cb_string_new(bucket_name));
|
4089
|
+
}
|
4090
|
+
|
4091
|
+
orchestrator_options.consistent_with = core_mut_state;
|
4092
|
+
}
|
4093
|
+
}
|
4094
|
+
|
4095
|
+
auto bucket_name = cb_string_new(bucket);
|
4096
|
+
auto scope_name = cb_string_new(scope);
|
4097
|
+
auto collection_name = cb_string_new(collection);
|
4098
|
+
|
4099
|
+
// Getting the operation agent
|
4100
|
+
auto agent_group = couchbase::core::agent_group(cluster->io_context(), couchbase::core::agent_group_config{ { cluster } });
|
4101
|
+
agent_group.open_bucket(bucket_name);
|
4102
|
+
auto agent = agent_group.get_agent(bucket_name);
|
4103
|
+
if (!agent.has_value()) {
|
4104
|
+
rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get operation agent");
|
4105
|
+
return Qnil;
|
4106
|
+
}
|
4107
|
+
|
4108
|
+
// Getting the vbucket map
|
4109
|
+
auto barrier = std::make_shared<std::promise<tl::expected<couchbase::core::topology::configuration, std::error_code>>>();
|
4110
|
+
auto f = barrier->get_future();
|
4111
|
+
cluster->with_bucket_configuration(bucket_name,
|
4112
|
+
[barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
|
4113
|
+
if (ec) {
|
4114
|
+
return barrier->set_value(tl::unexpected(ec));
|
4115
|
+
}
|
4116
|
+
barrier->set_value(config);
|
4117
|
+
});
|
4118
|
+
auto config = cb_wait_for_future(f);
|
4119
|
+
if (!config.has_value()) {
|
4120
|
+
rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get bucket configuration");
|
4121
|
+
return Qnil;
|
4122
|
+
}
|
4123
|
+
if (!config->supports_range_scan()) {
|
4124
|
+
rb_raise(eFeatureNotAvailable, "Server does not support key-value scan operations");
|
4125
|
+
return Qnil;
|
4126
|
+
}
|
4127
|
+
auto vbucket_map = config->vbmap;
|
4128
|
+
if (!vbucket_map || vbucket_map->empty()) {
|
4129
|
+
rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get vbucket map");
|
4130
|
+
return Qnil;
|
4131
|
+
}
|
4132
|
+
|
4133
|
+
// Constructing the scan type
|
4134
|
+
std::variant<std::monostate, couchbase::core::range_scan, couchbase::core::prefix_scan, couchbase::core::sampling_scan>
|
4135
|
+
core_scan_type{};
|
4136
|
+
ID scan_type_id = rb_sym2id(rb_hash_aref(scan_type, rb_id2sym(rb_intern("scan_type"))));
|
4137
|
+
if (scan_type_id == rb_intern("range")) {
|
4138
|
+
auto range_scan = couchbase::core::range_scan{};
|
4139
|
+
|
4140
|
+
VALUE from_hash = rb_hash_aref(scan_type, rb_id2sym(rb_intern("from")));
|
4141
|
+
VALUE to_hash = rb_hash_aref(scan_type, rb_id2sym(rb_intern("to")));
|
4142
|
+
|
4143
|
+
if (!NIL_P(from_hash)) {
|
4144
|
+
Check_Type(from_hash, T_HASH);
|
4145
|
+
range_scan.from = couchbase::core::scan_term{};
|
4146
|
+
cb_extract_option_string(range_scan.from->term, from_hash, "term");
|
4147
|
+
cb_extract_option_bool(range_scan.from->exclusive, from_hash, "exclusive");
|
4148
|
+
}
|
4149
|
+
if (!NIL_P(to_hash)) {
|
4150
|
+
Check_Type(to_hash, T_HASH);
|
4151
|
+
range_scan.to = couchbase::core::scan_term{};
|
4152
|
+
cb_extract_option_string(range_scan.to->term, to_hash, "term");
|
4153
|
+
cb_extract_option_bool(range_scan.to->exclusive, to_hash, "exclusive");
|
4154
|
+
}
|
4155
|
+
core_scan_type = range_scan;
|
4156
|
+
} else if (scan_type_id == rb_intern("prefix")) {
|
4157
|
+
auto prefix_scan = couchbase::core::prefix_scan{};
|
4158
|
+
cb_extract_option_string(prefix_scan.prefix, scan_type, "prefix");
|
4159
|
+
core_scan_type = prefix_scan;
|
4160
|
+
} else if (scan_type_id == rb_intern("sampling")) {
|
4161
|
+
auto sampling_scan = couchbase::core::sampling_scan{};
|
4162
|
+
cb_extract_option_number(sampling_scan.limit, scan_type, "limit");
|
4163
|
+
cb_extract_option_number(sampling_scan.seed, scan_type, "seed");
|
4164
|
+
core_scan_type = sampling_scan;
|
4165
|
+
} else {
|
4166
|
+
rb_raise(eInvalidArgument, "Invalid scan operation type");
|
4167
|
+
}
|
4168
|
+
|
4169
|
+
auto orchestrator = couchbase::core::range_scan_orchestrator(
|
4170
|
+
cluster->io_context(), agent.value(), vbucket_map.value(), scope_name, collection_name, core_scan_type, orchestrator_options);
|
4171
|
+
|
4172
|
+
// Start the scan
|
4173
|
+
auto resp = orchestrator.scan();
|
4174
|
+
if (!resp.has_value()) {
|
4175
|
+
cb_throw_error_code(resp.error(), "unable to start scan");
|
4176
|
+
}
|
4177
|
+
|
4178
|
+
// Wrap core scan_result inside Ruby ScanResult
|
4179
|
+
// Creating a Ruby CoreScanResult object *after* checking that no error occurred during orchestrator.scan()
|
4180
|
+
VALUE cCoreScanResult = rb_define_class_under(rb_define_module("Couchbase"), "CoreScanResult", rb_cObject);
|
4181
|
+
rb_define_alloc_func(cCoreScanResult, cb_CoreScanResult_allocate);
|
4182
|
+
rb_define_method(cCoreScanResult, "next_item", VALUE_FUNC(cb_CoreScanResult_next_item), 0);
|
4183
|
+
rb_define_method(cCoreScanResult, "cancelled?", VALUE_FUNC(cb_CoreScanResult_is_cancelled), 0);
|
4184
|
+
rb_define_method(cCoreScanResult, "cancel", VALUE_FUNC(cb_CoreScanResult_cancel), 0);
|
4185
|
+
VALUE core_scan_result_obj = rb_class_new_instance(0, NULL, cCoreScanResult);
|
4186
|
+
rb_ivar_set(core_scan_result_obj, rb_intern("@backend"), self);
|
4187
|
+
cb_core_scan_result_data* data = nullptr;
|
4188
|
+
TypedData_Get_Struct(core_scan_result_obj, cb_core_scan_result_data, &cb_core_scan_result_type, data);
|
4189
|
+
data->scan_result = std::make_unique<couchbase::core::scan_result>(resp.value());
|
4190
|
+
return core_scan_result_obj;
|
4191
|
+
|
4192
|
+
} catch (const std::system_error& se) {
|
4193
|
+
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
|
4194
|
+
} catch (const ruby_exception& e) {
|
4195
|
+
rb_exc_raise(e.exception_object());
|
4196
|
+
}
|
4197
|
+
return Qnil;
|
4198
|
+
}
|
4199
|
+
|
3664
4200
|
static int
|
3665
4201
|
cb_for_each_named_param(VALUE key, VALUE value, VALUE arg)
|
3666
4202
|
{
|
@@ -3696,6 +4232,7 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
|
|
3696
4232
|
cb_extract_option_bool(req.readonly, options, "readonly");
|
3697
4233
|
cb_extract_option_bool(req.flex_index, options, "flex_index");
|
3698
4234
|
cb_extract_option_bool(req.preserve_expiry, options, "preserve_expiry");
|
4235
|
+
cb_extract_option_bool(req.use_replica, options, "use_replica");
|
3699
4236
|
cb_extract_option_uint64(req.scan_cap, options, "scan_cap");
|
3700
4237
|
cb_extract_duration(req.scan_wait, options, "scan_wait");
|
3701
4238
|
cb_extract_option_uint64(req.max_parallelism, options, "max_parallelism");
|
@@ -8577,10 +9114,20 @@ cb_Backend_form_encode(VALUE self, VALUE data)
|
|
8577
9114
|
return cb_str_new(encoded);
|
8578
9115
|
}
|
8579
9116
|
|
9117
|
+
static VALUE
|
9118
|
+
cb_Backend_enable_protocol_logger_to_save_network_traffic_to_file(VALUE /* self */, VALUE path)
|
9119
|
+
{
|
9120
|
+
Check_Type(path, T_STRING);
|
9121
|
+
couchbase::core::logger::configuration configuration{};
|
9122
|
+
configuration.filename = cb_string_new(path);
|
9123
|
+
couchbase::core::logger::create_protocol_logger(configuration);
|
9124
|
+
return Qnil;
|
9125
|
+
}
|
9126
|
+
|
8580
9127
|
static void
|
8581
9128
|
init_backend(VALUE mCouchbase)
|
8582
9129
|
{
|
8583
|
-
VALUE cBackend = rb_define_class_under(mCouchbase, "Backend",
|
9130
|
+
VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cObject);
|
8584
9131
|
rb_define_alloc_func(cBackend, cb_Backend_allocate);
|
8585
9132
|
rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open), 3);
|
8586
9133
|
rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
|
@@ -8604,7 +9151,10 @@ init_backend(VALUE mCouchbase)
|
|
8604
9151
|
rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 5);
|
8605
9152
|
rb_define_method(cBackend, "document_remove_multi", VALUE_FUNC(cb_Backend_document_remove_multi), 5);
|
8606
9153
|
rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 6);
|
9154
|
+
rb_define_method(cBackend, "document_lookup_in_any_replica", VALUE_FUNC(cb_Backend_document_lookup_in_any_replica), 6);
|
9155
|
+
rb_define_method(cBackend, "document_lookup_in_all_replicas", VALUE_FUNC(cb_Backend_document_lookup_in_all_replicas), 6);
|
8607
9156
|
rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 6);
|
9157
|
+
rb_define_method(cBackend, "document_scan_create", VALUE_FUNC(cb_Backend_document_scan_create), 5);
|
8608
9158
|
rb_define_method(cBackend, "document_query", VALUE_FUNC(cb_Backend_document_query), 2);
|
8609
9159
|
rb_define_method(cBackend, "document_touch", VALUE_FUNC(cb_Backend_document_touch), 6);
|
8610
9160
|
rb_define_method(cBackend, "document_exists", VALUE_FUNC(cb_Backend_document_exists), 5);
|
@@ -8706,6 +9256,10 @@ init_backend(VALUE mCouchbase)
|
|
8706
9256
|
rb_define_singleton_method(cBackend, "query_escape", VALUE_FUNC(cb_Backend_query_escape), 1);
|
8707
9257
|
rb_define_singleton_method(cBackend, "path_escape", VALUE_FUNC(cb_Backend_path_escape), 1);
|
8708
9258
|
rb_define_singleton_method(cBackend, "form_encode", VALUE_FUNC(cb_Backend_form_encode), 1);
|
9259
|
+
rb_define_singleton_method(cBackend,
|
9260
|
+
"enable_protocol_logger_to_save_network_traffic_to_file",
|
9261
|
+
VALUE_FUNC(cb_Backend_enable_protocol_logger_to_save_network_traffic_to_file),
|
9262
|
+
1);
|
8709
9263
|
}
|
8710
9264
|
|
8711
9265
|
void
|