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