couchbase 3.0.0.alpha.2 → 3.0.0.alpha.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-dev-preview.yml +52 -0
  3. data/.gitmodules +3 -0
  4. data/.idea/vcs.xml +1 -0
  5. data/.yardopts +1 -0
  6. data/README.md +1 -1
  7. data/Rakefile +5 -1
  8. data/bin/init-cluster +13 -5
  9. data/couchbase.gemspec +2 -1
  10. data/examples/managing_query_indexes.rb +1 -1
  11. data/examples/managing_search_indexes.rb +62 -0
  12. data/examples/search.rb +187 -0
  13. data/ext/.clang-tidy +1 -0
  14. data/ext/build_version.hxx.in +1 -1
  15. data/ext/couchbase/bucket.hxx +0 -40
  16. data/ext/couchbase/couchbase.cxx +2578 -1368
  17. data/ext/couchbase/io/http_session.hxx +27 -7
  18. data/ext/couchbase/io/mcbp_parser.hxx +2 -0
  19. data/ext/couchbase/io/mcbp_session.hxx +53 -24
  20. data/ext/couchbase/io/session_manager.hxx +6 -1
  21. data/ext/couchbase/operations.hxx +13 -0
  22. data/ext/couchbase/operations/bucket_create.hxx +1 -0
  23. data/ext/couchbase/operations/bucket_drop.hxx +1 -0
  24. data/ext/couchbase/operations/bucket_flush.hxx +1 -0
  25. data/ext/couchbase/operations/bucket_get.hxx +1 -0
  26. data/ext/couchbase/operations/bucket_get_all.hxx +1 -0
  27. data/ext/couchbase/operations/bucket_update.hxx +1 -0
  28. data/ext/couchbase/operations/cluster_developer_preview_enable.hxx +1 -0
  29. data/ext/couchbase/operations/collection_create.hxx +6 -1
  30. data/ext/couchbase/operations/collection_drop.hxx +1 -0
  31. data/ext/couchbase/operations/command.hxx +86 -11
  32. data/ext/couchbase/operations/document_decrement.hxx +1 -0
  33. data/ext/couchbase/operations/document_exists.hxx +1 -0
  34. data/ext/couchbase/operations/document_get.hxx +1 -0
  35. data/ext/couchbase/operations/document_get_and_lock.hxx +1 -0
  36. data/ext/couchbase/operations/document_get_and_touch.hxx +1 -0
  37. data/ext/couchbase/operations/document_get_projected.hxx +243 -0
  38. data/ext/couchbase/operations/document_increment.hxx +4 -1
  39. data/ext/couchbase/operations/document_insert.hxx +1 -0
  40. data/ext/couchbase/operations/document_lookup_in.hxx +1 -0
  41. data/ext/couchbase/operations/document_mutate_in.hxx +1 -0
  42. data/ext/couchbase/operations/document_query.hxx +13 -2
  43. data/ext/couchbase/operations/document_remove.hxx +1 -0
  44. data/ext/couchbase/operations/document_replace.hxx +1 -0
  45. data/ext/couchbase/operations/document_search.hxx +337 -0
  46. data/ext/couchbase/operations/document_touch.hxx +1 -0
  47. data/ext/couchbase/operations/document_unlock.hxx +1 -0
  48. data/ext/couchbase/operations/document_upsert.hxx +1 -0
  49. data/ext/couchbase/operations/query_index_build_deferred.hxx +1 -0
  50. data/ext/couchbase/operations/query_index_create.hxx +1 -0
  51. data/ext/couchbase/operations/query_index_drop.hxx +1 -0
  52. data/ext/couchbase/operations/query_index_get_all.hxx +1 -0
  53. data/ext/couchbase/operations/scope_create.hxx +1 -0
  54. data/ext/couchbase/operations/scope_drop.hxx +1 -0
  55. data/ext/couchbase/operations/scope_get_all.hxx +2 -0
  56. data/ext/couchbase/operations/search_index.hxx +62 -0
  57. data/ext/couchbase/operations/search_index_analyze_document.hxx +92 -0
  58. data/ext/couchbase/operations/search_index_control_ingest.hxx +78 -0
  59. data/ext/couchbase/operations/search_index_control_plan_freeze.hxx +80 -0
  60. data/ext/couchbase/operations/search_index_control_query.hxx +80 -0
  61. data/ext/couchbase/operations/search_index_drop.hxx +77 -0
  62. data/ext/couchbase/operations/search_index_get.hxx +80 -0
  63. data/ext/couchbase/operations/search_index_get_all.hxx +82 -0
  64. data/ext/couchbase/operations/search_index_get_documents_count.hxx +81 -0
  65. data/ext/couchbase/operations/search_index_upsert.hxx +106 -0
  66. data/ext/couchbase/protocol/client_opcode.hxx +10 -0
  67. data/ext/couchbase/protocol/cmd_get_collection_id.hxx +117 -0
  68. data/ext/couchbase/timeout_defaults.hxx +32 -0
  69. data/ext/couchbase/version.hxx +1 -1
  70. data/ext/test/main.cxx +5 -5
  71. data/lib/couchbase/binary_collection.rb +16 -12
  72. data/lib/couchbase/binary_collection_options.rb +4 -0
  73. data/lib/couchbase/cluster.rb +88 -8
  74. data/lib/couchbase/collection.rb +39 -15
  75. data/lib/couchbase/collection_options.rb +19 -2
  76. data/lib/couchbase/json_transcoder.rb +2 -2
  77. data/lib/couchbase/management/bucket_manager.rb +37 -23
  78. data/lib/couchbase/management/collection_manager.rb +15 -6
  79. data/lib/couchbase/management/query_index_manager.rb +16 -6
  80. data/lib/couchbase/management/search_index_manager.rb +61 -14
  81. data/lib/couchbase/search_options.rb +1492 -0
  82. data/lib/couchbase/version.rb +1 -1
  83. metadata +22 -2
@@ -290,212 +290,213 @@ init_exceptions(VALUE mCouchbase)
290
290
  eXattrUnknownVirtualAttribute = rb_define_class_under(mError, "XattrUnknownVirtualAttribute", rb_eStandardError);
291
291
  }
292
292
 
293
- static NORETURN(void cb_raise_error_code(std::error_code ec, const std::string& message))
293
+ static VALUE
294
+ cb__map_error_code(std::error_code ec, const std::string& message)
294
295
  {
295
296
  if (ec.category() == couchbase::error::detail::get_common_category()) {
296
297
  switch (static_cast<couchbase::error::common_errc>(ec.value())) {
297
298
  case couchbase::error::common_errc::unambiguous_timeout:
298
- rb_raise(eUnambiguousTimeout, "%s: %s", message.c_str(), ec.message().c_str());
299
+ return rb_exc_new_cstr(eUnambiguousTimeout, fmt::format("{}: {}", message, ec.message()).c_str());
299
300
 
300
301
  case couchbase::error::common_errc::ambiguous_timeout:
301
- rb_raise(eAmbiguousTimeout, "%s: %s", message.c_str(), ec.message().c_str());
302
+ return rb_exc_new_cstr(eAmbiguousTimeout, fmt::format("{}: {}", message, ec.message()).c_str());
302
303
 
303
304
  case couchbase::error::common_errc::request_canceled:
304
- rb_raise(eRequestCanceled, "%s: %s", message.c_str(), ec.message().c_str());
305
+ return rb_exc_new_cstr(eRequestCanceled, fmt::format("{}: {}", message, ec.message()).c_str());
305
306
 
306
307
  case couchbase::error::common_errc::invalid_argument:
307
- rb_raise(eInvalidArgument, "%s: %s", message.c_str(), ec.message().c_str());
308
+ return rb_exc_new_cstr(eInvalidArgument, fmt::format("{}: {}", message, ec.message()).c_str());
308
309
 
309
310
  case couchbase::error::common_errc::service_not_available:
310
- rb_raise(eServiceNotAvailable, "%s: %s", message.c_str(), ec.message().c_str());
311
+ return rb_exc_new_cstr(eServiceNotAvailable, fmt::format("{}: {}", message, ec.message()).c_str());
311
312
 
312
313
  case couchbase::error::common_errc::internal_server_failure:
313
- rb_raise(eInternalServerFailure, "%s: %s", message.c_str(), ec.message().c_str());
314
+ return rb_exc_new_cstr(eInternalServerFailure, fmt::format("{}: {}", message, ec.message()).c_str());
314
315
 
315
316
  case couchbase::error::common_errc::authentication_failure:
316
- rb_raise(eAuthenticationFailure, "%s: %s", message.c_str(), ec.message().c_str());
317
+ return rb_exc_new_cstr(eAuthenticationFailure, fmt::format("{}: {}", message, ec.message()).c_str());
317
318
 
318
319
  case couchbase::error::common_errc::temporary_failure:
319
- rb_raise(eTemporaryFailure, "%s: %s", message.c_str(), ec.message().c_str());
320
+ return rb_exc_new_cstr(eTemporaryFailure, fmt::format("{}: {}", message, ec.message()).c_str());
320
321
 
321
322
  case couchbase::error::common_errc::parsing_failure:
322
- rb_raise(eParsingFailure, "%s: %s", message.c_str(), ec.message().c_str());
323
+ return rb_exc_new_cstr(eParsingFailure, fmt::format("{}: {}", message, ec.message()).c_str());
323
324
 
324
325
  case couchbase::error::common_errc::cas_mismatch:
325
- rb_raise(eCasMismatch, "%s: %s", message.c_str(), ec.message().c_str());
326
+ return rb_exc_new_cstr(eCasMismatch, fmt::format("{}: {}", message, ec.message()).c_str());
326
327
 
327
328
  case couchbase::error::common_errc::bucket_not_found:
328
- rb_raise(eBucketNotFound, "%s: %s", message.c_str(), ec.message().c_str());
329
+ return rb_exc_new_cstr(eBucketNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
329
330
 
330
331
  case couchbase::error::common_errc::scope_not_found:
331
- rb_raise(eScopeNotFound, "%s: %s", message.c_str(), ec.message().c_str());
332
+ return rb_exc_new_cstr(eScopeNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
332
333
 
333
334
  case couchbase::error::common_errc::collection_not_found:
334
- rb_raise(eCollectionNotFound, "%s: %s", message.c_str(), ec.message().c_str());
335
+ return rb_exc_new_cstr(eCollectionNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
335
336
 
336
337
  case couchbase::error::common_errc::unsupported_operation:
337
- rb_raise(eUnsupportedOperation, "%s: %s", message.c_str(), ec.message().c_str());
338
+ return rb_exc_new_cstr(eUnsupportedOperation, fmt::format("{}: {}", message, ec.message()).c_str());
338
339
 
339
340
  case couchbase::error::common_errc::feature_not_available:
340
- rb_raise(eFeatureNotAvailable, "%s: %s", message.c_str(), ec.message().c_str());
341
+ return rb_exc_new_cstr(eFeatureNotAvailable, fmt::format("{}: {}", message, ec.message()).c_str());
341
342
 
342
343
  case couchbase::error::common_errc::encoding_failure:
343
- rb_raise(eEncodingFailure, "%s: %s", message.c_str(), ec.message().c_str());
344
+ return rb_exc_new_cstr(eEncodingFailure, fmt::format("{}: {}", message, ec.message()).c_str());
344
345
 
345
346
  case couchbase::error::common_errc::decoding_failure:
346
- rb_raise(eDecodingFailure, "%s: %s", message.c_str(), ec.message().c_str());
347
+ return rb_exc_new_cstr(eDecodingFailure, fmt::format("{}: {}", message, ec.message()).c_str());
347
348
 
348
349
  case couchbase::error::common_errc::index_not_found:
349
- rb_raise(eIndexNotFound, "%s: %s", message.c_str(), ec.message().c_str());
350
+ return rb_exc_new_cstr(eIndexNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
350
351
 
351
352
  case couchbase::error::common_errc::index_exists:
352
- rb_raise(eIndexExists, "%s: %s", message.c_str(), ec.message().c_str());
353
+ return rb_exc_new_cstr(eIndexExists, fmt::format("{}: {}", message, ec.message()).c_str());
353
354
  }
354
355
  } else if (ec.category() == couchbase::error::detail::get_key_value_category()) {
355
356
  switch (static_cast<couchbase::error::key_value_errc>(ec.value())) {
356
357
  case couchbase::error::key_value_errc::document_not_found:
357
- rb_raise(eDocumentNotFound, "%s: %s", message.c_str(), ec.message().c_str());
358
+ return rb_exc_new_cstr(eDocumentNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
358
359
 
359
360
  case couchbase::error::key_value_errc::document_irretrievable:
360
- rb_raise(eDocumentIrretrievable, "%s: %s", message.c_str(), ec.message().c_str());
361
+ return rb_exc_new_cstr(eDocumentIrretrievable, fmt::format("{}: {}", message, ec.message()).c_str());
361
362
 
362
363
  case couchbase::error::key_value_errc::document_locked:
363
- rb_raise(eDocumentLocked, "%s: %s", message.c_str(), ec.message().c_str());
364
+ return rb_exc_new_cstr(eDocumentLocked, fmt::format("{}: {}", message, ec.message()).c_str());
364
365
 
365
366
  case couchbase::error::key_value_errc::value_too_large:
366
- rb_raise(eValueTooLarge, "%s: %s", message.c_str(), ec.message().c_str());
367
+ return rb_exc_new_cstr(eValueTooLarge, fmt::format("{}: {}", message, ec.message()).c_str());
367
368
 
368
369
  case couchbase::error::key_value_errc::document_exists:
369
- rb_raise(eDocumentExists, "%s: %s", message.c_str(), ec.message().c_str());
370
+ return rb_exc_new_cstr(eDocumentExists, fmt::format("{}: {}", message, ec.message()).c_str());
370
371
 
371
372
  case couchbase::error::key_value_errc::durability_level_not_available:
372
- rb_raise(eDurabilityLevelNotAvailable, "%s: %s", message.c_str(), ec.message().c_str());
373
+ return rb_exc_new_cstr(eDurabilityLevelNotAvailable, fmt::format("{}: {}", message, ec.message()).c_str());
373
374
 
374
375
  case couchbase::error::key_value_errc::durability_impossible:
375
- rb_raise(eDurabilityImpossible, "%s: %s", message.c_str(), ec.message().c_str());
376
+ return rb_exc_new_cstr(eDurabilityImpossible, fmt::format("{}: {}", message, ec.message()).c_str());
376
377
 
377
378
  case couchbase::error::key_value_errc::durability_ambiguous:
378
- rb_raise(eDurabilityAmbiguous, "%s: %s", message.c_str(), ec.message().c_str());
379
+ return rb_exc_new_cstr(eDurabilityAmbiguous, fmt::format("{}: {}", message, ec.message()).c_str());
379
380
 
380
381
  case couchbase::error::key_value_errc::durable_write_in_progress:
381
- rb_raise(eDurableWriteInProgress, "%s: %s", message.c_str(), ec.message().c_str());
382
+ return rb_exc_new_cstr(eDurableWriteInProgress, fmt::format("{}: {}", message, ec.message()).c_str());
382
383
 
383
384
  case couchbase::error::key_value_errc::durable_write_re_commit_in_progress:
384
- rb_raise(eDurableWriteReCommitInProgress, "%s: %s", message.c_str(), ec.message().c_str());
385
+ return rb_exc_new_cstr(eDurableWriteReCommitInProgress, fmt::format("{}: {}", message, ec.message()).c_str());
385
386
 
386
387
  case couchbase::error::key_value_errc::path_not_found:
387
- rb_raise(ePathNotFound, "%s: %s", message.c_str(), ec.message().c_str());
388
+ return rb_exc_new_cstr(ePathNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
388
389
 
389
390
  case couchbase::error::key_value_errc::path_mismatch:
390
- rb_raise(ePathMismatch, "%s: %s", message.c_str(), ec.message().c_str());
391
+ return rb_exc_new_cstr(ePathMismatch, fmt::format("{}: {}", message, ec.message()).c_str());
391
392
 
392
393
  case couchbase::error::key_value_errc::path_invalid:
393
- rb_raise(ePathInvalid, "%s: %s", message.c_str(), ec.message().c_str());
394
+ return rb_exc_new_cstr(ePathInvalid, fmt::format("{}: {}", message, ec.message()).c_str());
394
395
 
395
396
  case couchbase::error::key_value_errc::path_too_big:
396
- rb_raise(ePathTooBig, "%s: %s", message.c_str(), ec.message().c_str());
397
+ return rb_exc_new_cstr(ePathTooBig, fmt::format("{}: {}", message, ec.message()).c_str());
397
398
 
398
399
  case couchbase::error::key_value_errc::path_too_deep:
399
- rb_raise(ePathTooDeep, "%s: %s", message.c_str(), ec.message().c_str());
400
+ return rb_exc_new_cstr(ePathTooDeep, fmt::format("{}: {}", message, ec.message()).c_str());
400
401
 
401
402
  case couchbase::error::key_value_errc::value_too_deep:
402
- rb_raise(eValueTooDeep, "%s: %s", message.c_str(), ec.message().c_str());
403
+ return rb_exc_new_cstr(eValueTooDeep, fmt::format("{}: {}", message, ec.message()).c_str());
403
404
 
404
405
  case couchbase::error::key_value_errc::value_invalid:
405
- rb_raise(eValueInvalid, "%s: %s", message.c_str(), ec.message().c_str());
406
+ return rb_exc_new_cstr(eValueInvalid, fmt::format("{}: {}", message, ec.message()).c_str());
406
407
 
407
408
  case couchbase::error::key_value_errc::document_not_json:
408
- rb_raise(eDocumentNotJson, "%s: %s", message.c_str(), ec.message().c_str());
409
+ return rb_exc_new_cstr(eDocumentNotJson, fmt::format("{}: {}", message, ec.message()).c_str());
409
410
 
410
411
  case couchbase::error::key_value_errc::number_too_big:
411
- rb_raise(eNumberTooBig, "%s: %s", message.c_str(), ec.message().c_str());
412
+ return rb_exc_new_cstr(eNumberTooBig, fmt::format("{}: {}", message, ec.message()).c_str());
412
413
 
413
414
  case couchbase::error::key_value_errc::delta_invalid:
414
- rb_raise(eDeltaInvalid, "%s: %s", message.c_str(), ec.message().c_str());
415
+ return rb_exc_new_cstr(eDeltaInvalid, fmt::format("{}: {}", message, ec.message()).c_str());
415
416
 
416
417
  case couchbase::error::key_value_errc::path_exists:
417
- rb_raise(ePathExists, "%s: %s", message.c_str(), ec.message().c_str());
418
+ return rb_exc_new_cstr(ePathExists, fmt::format("{}: {}", message, ec.message()).c_str());
418
419
 
419
420
  case couchbase::error::key_value_errc::xattr_unknown_macro:
420
- rb_raise(eXattrUnknownMacro, "%s: %s", message.c_str(), ec.message().c_str());
421
+ return rb_exc_new_cstr(eXattrUnknownMacro, fmt::format("{}: {}", message, ec.message()).c_str());
421
422
 
422
423
  case couchbase::error::key_value_errc::xattr_invalid_key_combo:
423
- rb_raise(eXattrInvalidKeyCombo, "%s: %s", message.c_str(), ec.message().c_str());
424
+ return rb_exc_new_cstr(eXattrInvalidKeyCombo, fmt::format("{}: {}", message, ec.message()).c_str());
424
425
 
425
426
  case couchbase::error::key_value_errc::xattr_unknown_virtual_attribute:
426
- rb_raise(eXattrUnknownVirtualAttribute, "%s: %s", message.c_str(), ec.message().c_str());
427
+ return rb_exc_new_cstr(eXattrUnknownVirtualAttribute, fmt::format("{}: {}", message, ec.message()).c_str());
427
428
 
428
429
  case couchbase::error::key_value_errc::xattr_cannot_modify_virtual_attribute:
429
- rb_raise(eXattrCannotModifyVirtualAttribute, "%s: %s", message.c_str(), ec.message().c_str());
430
+ return rb_exc_new_cstr(eXattrCannotModifyVirtualAttribute, fmt::format("{}: {}", message, ec.message()).c_str());
430
431
  }
431
432
  } else if (ec.category() == couchbase::error::detail::get_query_category()) {
432
433
  switch (static_cast<couchbase::error::query_errc>(ec.value())) {
433
434
  case couchbase::error::query_errc::planning_failure:
434
- rb_raise(ePlanningFailure, "%s: %s", message.c_str(), ec.message().c_str());
435
+ return rb_exc_new_cstr(ePlanningFailure, fmt::format("{}: {}", message, ec.message()).c_str());
435
436
 
436
437
  case couchbase::error::query_errc::index_failure:
437
- rb_raise(eIndexFailure, "%s: %s", message.c_str(), ec.message().c_str());
438
+ return rb_exc_new_cstr(eIndexFailure, fmt::format("{}: {}", message, ec.message()).c_str());
438
439
 
439
440
  case couchbase::error::query_errc::prepared_statement_failure:
440
- rb_raise(ePreparedStatementFailure, "%s: %s", message.c_str(), ec.message().c_str());
441
+ return rb_exc_new_cstr(ePreparedStatementFailure, fmt::format("{}: {}", message, ec.message()).c_str());
441
442
  }
442
443
  } else if (ec.category() == couchbase::error::detail::get_view_category()) {
443
444
  switch (static_cast<couchbase::error::view_errc>(ec.value())) {
444
445
  case couchbase::error::view_errc::view_not_found:
445
- rb_raise(eViewNotFound, "%s: %s", message.c_str(), ec.message().c_str());
446
+ return rb_exc_new_cstr(eViewNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
446
447
 
447
448
  case couchbase::error::view_errc::design_document_not_found:
448
- rb_raise(eDesignDocumentNotFound, "%s: %s", message.c_str(), ec.message().c_str());
449
+ return rb_exc_new_cstr(eDesignDocumentNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
449
450
  }
450
451
  } else if (ec.category() == couchbase::error::detail::get_analytics_category()) {
451
452
  switch (static_cast<couchbase::error::analytics_errc>(ec.value())) {
452
453
  case couchbase::error::analytics_errc::compilation_failure:
453
- rb_raise(eCompilationFailure, "%s: %s", message.c_str(), ec.message().c_str());
454
+ return rb_exc_new_cstr(eCompilationFailure, fmt::format("{}: {}", message, ec.message()).c_str());
454
455
 
455
456
  case couchbase::error::analytics_errc::job_queue_full:
456
- rb_raise(eJobQueueFull, "%s: %s", message.c_str(), ec.message().c_str());
457
+ return rb_exc_new_cstr(eJobQueueFull, fmt::format("{}: {}", message, ec.message()).c_str());
457
458
 
458
459
  case couchbase::error::analytics_errc::dataset_not_found:
459
- rb_raise(eDatasetNotFound, "%s: %s", message.c_str(), ec.message().c_str());
460
+ return rb_exc_new_cstr(eDatasetNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
460
461
 
461
462
  case couchbase::error::analytics_errc::dataverse_not_found:
462
- rb_raise(eDataverseNotFound, "%s: %s", message.c_str(), ec.message().c_str());
463
+ return rb_exc_new_cstr(eDataverseNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
463
464
 
464
465
  case couchbase::error::analytics_errc::dataset_exists:
465
- rb_raise(eDatasetExists, "%s: %s", message.c_str(), ec.message().c_str());
466
+ return rb_exc_new_cstr(eDatasetExists, fmt::format("{}: {}", message, ec.message()).c_str());
466
467
 
467
468
  case couchbase::error::analytics_errc::dataverse_exists:
468
- rb_raise(eDataverseExists, "%s: %s", message.c_str(), ec.message().c_str());
469
+ return rb_exc_new_cstr(eDataverseExists, fmt::format("{}: {}", message, ec.message()).c_str());
469
470
 
470
471
  case couchbase::error::analytics_errc::link_not_found:
471
- rb_raise(eLinkNotFound, "%s: %s", message.c_str(), ec.message().c_str());
472
+ return rb_exc_new_cstr(eLinkNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
472
473
  }
473
474
  } else if (ec.category() == couchbase::error::detail::get_management_category()) {
474
475
  switch (static_cast<couchbase::error::management_errc>(ec.value())) {
475
476
  case couchbase::error::management_errc::collection_exists:
476
- rb_raise(eCollectionExists, "%s: %s", message.c_str(), ec.message().c_str());
477
+ return rb_exc_new_cstr(eCollectionExists, fmt::format("{}: {}", message, ec.message()).c_str());
477
478
 
478
479
  case couchbase::error::management_errc::scope_exists:
479
- rb_raise(eScopeExists, "%s: %s", message.c_str(), ec.message().c_str());
480
+ return rb_exc_new_cstr(eScopeExists, fmt::format("{}: {}", message, ec.message()).c_str());
480
481
 
481
482
  case couchbase::error::management_errc::user_not_found:
482
- rb_raise(eUserNotFound, "%s: %s", message.c_str(), ec.message().c_str());
483
+ return rb_exc_new_cstr(eUserNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
483
484
 
484
485
  case couchbase::error::management_errc::group_not_found:
485
- rb_raise(eGroupNotFound, "%s: %s", message.c_str(), ec.message().c_str());
486
+ return rb_exc_new_cstr(eGroupNotFound, fmt::format("{}: {}", message, ec.message()).c_str());
486
487
 
487
488
  case couchbase::error::management_errc::user_exists:
488
- rb_raise(eUserExists, "%s: %s", message.c_str(), ec.message().c_str());
489
+ return rb_exc_new_cstr(eUserExists, fmt::format("{}: {}", message, ec.message()).c_str());
489
490
 
490
491
  case couchbase::error::management_errc::bucket_exists:
491
- rb_raise(eBucketExists, "%s: %s", message.c_str(), ec.message().c_str());
492
+ return rb_exc_new_cstr(eBucketExists, fmt::format("{}: {}", message, ec.message()).c_str());
492
493
 
493
494
  case couchbase::error::management_errc::bucket_not_flushable:
494
- rb_raise(eBucketNotFlushable, "%s: %s", message.c_str(), ec.message().c_str());
495
+ return rb_exc_new_cstr(eBucketNotFlushable, fmt::format("{}: {}", message, ec.message()).c_str());
495
496
  }
496
497
  }
497
498
 
498
- rb_raise(eBackendError, "%s: %s", message.c_str(), ec.message().c_str());
499
+ return rb_exc_new_cstr(eBackendError, fmt::format("{}: {}", message, ec.message()).c_str());
499
500
  }
500
501
 
501
502
  static VALUE
@@ -507,20 +508,26 @@ cb_Backend_open(VALUE self, VALUE hostname, VALUE username, VALUE password)
507
508
  if (!backend->cluster) {
508
509
  rb_raise(rb_eArgError, "Cluster has been closed already");
509
510
  }
511
+ VALUE exc = Qnil;
510
512
 
511
- Check_Type(hostname, T_STRING);
512
- Check_Type(username, T_STRING);
513
- Check_Type(password, T_STRING);
514
-
515
- couchbase::origin options;
516
- options.hostname.assign(RSTRING_PTR(hostname), static_cast<size_t>(RSTRING_LEN(hostname)));
517
- options.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
518
- options.password.assign(RSTRING_PTR(password), static_cast<size_t>(RSTRING_LEN(password)));
519
- auto barrier = std::make_shared<std::promise<std::error_code>>();
520
- auto f = barrier->get_future();
521
- backend->cluster->open(options, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
522
- if (auto ec = f.get()) {
523
- cb_raise_error_code(ec, fmt::format("unable open cluster at {}", options.hostname));
513
+ {
514
+ Check_Type(hostname, T_STRING);
515
+ Check_Type(username, T_STRING);
516
+ Check_Type(password, T_STRING);
517
+
518
+ couchbase::origin options;
519
+ options.hostname.assign(RSTRING_PTR(hostname), static_cast<size_t>(RSTRING_LEN(hostname)));
520
+ options.username.assign(RSTRING_PTR(username), static_cast<size_t>(RSTRING_LEN(username)));
521
+ options.password.assign(RSTRING_PTR(password), static_cast<size_t>(RSTRING_LEN(password)));
522
+ auto barrier = std::make_shared<std::promise<std::error_code>>();
523
+ auto f = barrier->get_future();
524
+ backend->cluster->open(options, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
525
+ if (auto ec = f.get()) {
526
+ exc = cb__map_error_code(ec, fmt::format("unable open cluster at {}", options.hostname));
527
+ }
528
+ }
529
+ if (!NIL_P(exc)) {
530
+ rb_exc_raise(exc);
524
531
  }
525
532
 
526
533
  return Qnil;
@@ -546,20 +553,43 @@ cb_Backend_open_bucket(VALUE self, VALUE bucket)
546
553
  }
547
554
 
548
555
  Check_Type(bucket, T_STRING);
549
- std::string name(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
550
556
 
551
- auto barrier = std::make_shared<std::promise<std::error_code>>();
552
- auto f = barrier->get_future();
553
- backend->cluster->open_bucket(name, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
554
- if (auto ec = f.get()) {
555
- cb_raise_error_code(ec, fmt::format("unable open bucket \"{}\"", name));
557
+ VALUE exc = Qnil;
558
+ {
559
+ std::string name(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
560
+
561
+ auto barrier = std::make_shared<std::promise<std::error_code>>();
562
+ auto f = barrier->get_future();
563
+ backend->cluster->open_bucket(name, [barrier](std::error_code ec) mutable { barrier->set_value(ec); });
564
+ if (auto ec = f.get()) {
565
+ exc = cb__map_error_code(ec, fmt::format("unable open bucket \"{}\"", name));
566
+ }
567
+ }
568
+ if (!NIL_P(exc)) {
569
+ rb_exc_raise(exc);
556
570
  }
557
571
 
558
572
  return Qtrue;
559
573
  }
560
574
 
575
+ template<typename Request>
576
+ void
577
+ cb__extract_timeout(Request& req, VALUE timeout)
578
+ {
579
+ if (!NIL_P(timeout)) {
580
+ switch (TYPE(timeout)) {
581
+ case T_FIXNUM:
582
+ case T_BIGNUM:
583
+ req.timeout = std::chrono::milliseconds(NUM2ULL(timeout));
584
+ break;
585
+ default:
586
+ rb_raise(rb_eArgError, "timeout must be an Integer");
587
+ }
588
+ }
589
+ }
590
+
561
591
  static VALUE
562
- cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id)
592
+ cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout)
563
593
  {
564
594
  cb_backend_data* backend = nullptr;
565
595
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -572,29 +602,101 @@ cb_Backend_document_get(VALUE self, VALUE bucket, VALUE collection, VALUE id)
572
602
  Check_Type(collection, T_STRING);
573
603
  Check_Type(id, T_STRING);
574
604
 
575
- couchbase::document_id doc_id;
576
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
577
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
578
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
605
+ VALUE exc = Qnil;
606
+ do {
607
+ couchbase::document_id doc_id;
608
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
609
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
610
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
611
+
612
+ couchbase::operations::get_request req{ doc_id };
613
+ cb__extract_timeout(req, timeout);
614
+ auto barrier = std::make_shared<std::promise<couchbase::operations::get_response>>();
615
+ auto f = barrier->get_future();
616
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_response resp) mutable { barrier->set_value(resp); });
617
+ auto resp = f.get();
618
+ if (resp.ec) {
619
+ exc = cb__map_error_code(resp.ec, fmt::format("unable fetch {}", doc_id));
620
+ break;
621
+ }
622
+
623
+ VALUE res = rb_hash_new();
624
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
625
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
626
+ rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
627
+ return res;
628
+ } while (false);
629
+ rb_exc_raise(exc);
630
+ return Qnil;
631
+ }
632
+
633
+ static VALUE
634
+ cb_Backend_document_get_projected(VALUE self,
635
+ VALUE bucket,
636
+ VALUE collection,
637
+ VALUE id,
638
+ VALUE timeout,
639
+ VALUE with_expiration,
640
+ VALUE projections,
641
+ VALUE preserve_array_indexes)
642
+ {
643
+ cb_backend_data* backend = nullptr;
644
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
579
645
 
580
- couchbase::operations::get_request req{ doc_id };
581
- auto barrier = std::make_shared<std::promise<couchbase::operations::get_response>>();
582
- auto f = barrier->get_future();
583
- backend->cluster->execute(req, [barrier](couchbase::operations::get_response resp) mutable { barrier->set_value(resp); });
584
- auto resp = f.get();
585
- if (resp.ec) {
586
- cb_raise_error_code(resp.ec, fmt::format("unable fetch {}", doc_id));
646
+ if (!backend->cluster) {
647
+ rb_raise(rb_eArgError, "Cluster has been closed already");
587
648
  }
588
649
 
589
- VALUE res = rb_hash_new();
590
- rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
591
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
592
- rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
593
- return res;
650
+ Check_Type(bucket, T_STRING);
651
+ Check_Type(collection, T_STRING);
652
+ Check_Type(id, T_STRING);
653
+
654
+ VALUE exc = Qnil;
655
+ do {
656
+ couchbase::document_id doc_id;
657
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
658
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
659
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
660
+
661
+ couchbase::operations::get_projected_request req{ doc_id };
662
+ cb__extract_timeout(req, timeout);
663
+ req.with_expiration = RTEST(with_expiration);
664
+ req.preserve_array_indexes = RTEST(preserve_array_indexes);
665
+ if (!NIL_P(projections)) {
666
+ Check_Type(projections, T_ARRAY);
667
+ auto entries_num = static_cast<size_t>(RARRAY_LEN(projections));
668
+ req.projections.reserve(entries_num);
669
+ for (size_t i = 0; i < entries_num; ++i) {
670
+ VALUE entry = rb_ary_entry(projections, static_cast<long>(i));
671
+ Check_Type(entry, T_STRING);
672
+ req.projections.emplace_back(std::string(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry))));
673
+ }
674
+ }
675
+
676
+ auto barrier = std::make_shared<std::promise<couchbase::operations::get_projected_response>>();
677
+ auto f = barrier->get_future();
678
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_projected_response resp) mutable { barrier->set_value(resp); });
679
+ auto resp = f.get();
680
+ if (resp.ec) {
681
+ exc = cb__map_error_code(resp.ec, fmt::format("unable fetch with projections {}", doc_id));
682
+ break;
683
+ }
684
+
685
+ VALUE res = rb_hash_new();
686
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
687
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
688
+ rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
689
+ if (resp.expiration) {
690
+ rb_hash_aset(res, rb_id2sym(rb_intern("expiration")), UINT2NUM(resp.expiration.value()));
691
+ }
692
+ return res;
693
+ } while (false);
694
+ rb_exc_raise(exc);
695
+ return Qnil;
594
696
  }
595
697
 
596
698
  static VALUE
597
- cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE lock_time)
699
+ cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE lock_time)
598
700
  {
599
701
  cb_backend_data* backend = nullptr;
600
702
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -608,31 +710,38 @@ cb_Backend_document_get_and_lock(VALUE self, VALUE bucket, VALUE collection, VAL
608
710
  Check_Type(id, T_STRING);
609
711
  Check_Type(lock_time, T_FIXNUM);
610
712
 
611
- couchbase::document_id doc_id;
612
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
613
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
614
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
713
+ VALUE exc = Qnil;
714
+ do {
715
+ couchbase::document_id doc_id;
716
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
717
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
718
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
615
719
 
616
- couchbase::operations::get_and_lock_request req{ doc_id };
617
- req.lock_time = NUM2UINT(lock_time);
720
+ couchbase::operations::get_and_lock_request req{ doc_id };
721
+ cb__extract_timeout(req, timeout);
722
+ req.lock_time = NUM2UINT(lock_time);
618
723
 
619
- auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_lock_response>>();
620
- auto f = barrier->get_future();
621
- backend->cluster->execute(req, [barrier](couchbase::operations::get_and_lock_response resp) mutable { barrier->set_value(resp); });
622
- auto resp = f.get();
623
- if (resp.ec) {
624
- cb_raise_error_code(resp.ec, fmt::format("unable lock and fetch {}", doc_id));
625
- }
724
+ auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_lock_response>>();
725
+ auto f = barrier->get_future();
726
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_and_lock_response resp) mutable { barrier->set_value(resp); });
727
+ auto resp = f.get();
728
+ if (resp.ec) {
729
+ exc = cb__map_error_code(resp.ec, fmt::format("unable lock and fetch {}", doc_id));
730
+ break;
731
+ }
626
732
 
627
- VALUE res = rb_hash_new();
628
- rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
629
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
630
- rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
631
- return res;
733
+ VALUE res = rb_hash_new();
734
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
735
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
736
+ rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
737
+ return res;
738
+ } while (false);
739
+ rb_exc_raise(exc);
740
+ return Qnil;
632
741
  }
633
742
 
634
743
  static VALUE
635
- cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE expiration)
744
+ cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE expiration)
636
745
  {
637
746
  cb_backend_data* backend = nullptr;
638
747
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -646,27 +755,34 @@ cb_Backend_document_get_and_touch(VALUE self, VALUE bucket, VALUE collection, VA
646
755
  Check_Type(id, T_STRING);
647
756
  Check_Type(expiration, T_FIXNUM);
648
757
 
649
- couchbase::document_id doc_id;
650
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
651
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
652
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
758
+ VALUE exc = Qnil;
759
+ do {
760
+ couchbase::document_id doc_id;
761
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
762
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
763
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
653
764
 
654
- couchbase::operations::get_and_touch_request req{ doc_id };
655
- req.expiration = NUM2UINT(expiration);
765
+ couchbase::operations::get_and_touch_request req{ doc_id };
766
+ cb__extract_timeout(req, timeout);
767
+ req.expiration = NUM2UINT(expiration);
656
768
 
657
- auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_touch_response>>();
658
- auto f = barrier->get_future();
659
- backend->cluster->execute(req, [barrier](couchbase::operations::get_and_touch_response resp) mutable { barrier->set_value(resp); });
660
- auto resp = f.get();
661
- if (resp.ec) {
662
- cb_raise_error_code(resp.ec, fmt::format("unable fetch and touch {}", doc_id));
663
- }
769
+ auto barrier = std::make_shared<std::promise<couchbase::operations::get_and_touch_response>>();
770
+ auto f = barrier->get_future();
771
+ backend->cluster->execute(req, [barrier](couchbase::operations::get_and_touch_response resp) mutable { barrier->set_value(resp); });
772
+ auto resp = f.get();
773
+ if (resp.ec) {
774
+ exc = cb__map_error_code(resp.ec, fmt::format("unable fetch and touch {}", doc_id));
775
+ break;
776
+ }
664
777
 
665
- VALUE res = rb_hash_new();
666
- rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
667
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
668
- rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
669
- return res;
778
+ VALUE res = rb_hash_new();
779
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), rb_str_new(resp.value.data(), static_cast<long>(resp.value.size())));
780
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
781
+ rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(resp.flags));
782
+ return res;
783
+ } while (false);
784
+ rb_exc_raise(exc);
785
+ return Qnil;
670
786
  }
671
787
 
672
788
  template<typename Response>
@@ -687,7 +803,7 @@ cb__extract_mutation_result(Response resp)
687
803
  }
688
804
 
689
805
  static VALUE
690
- cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE expiration)
806
+ cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE expiration)
691
807
  {
692
808
  cb_backend_data* backend = nullptr;
693
809
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -701,29 +817,36 @@ cb_Backend_document_touch(VALUE self, VALUE bucket, VALUE collection, VALUE id,
701
817
  Check_Type(id, T_STRING);
702
818
  Check_Type(expiration, T_FIXNUM);
703
819
 
704
- couchbase::document_id doc_id;
705
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
706
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
707
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
820
+ VALUE exc = Qnil;
821
+ do {
822
+ couchbase::document_id doc_id;
823
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
824
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
825
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
708
826
 
709
- couchbase::operations::touch_request req{ doc_id };
710
- req.expiration = NUM2UINT(expiration);
827
+ couchbase::operations::touch_request req{ doc_id };
828
+ cb__extract_timeout(req, timeout);
829
+ req.expiration = NUM2UINT(expiration);
711
830
 
712
- auto barrier = std::make_shared<std::promise<couchbase::operations::touch_response>>();
713
- auto f = barrier->get_future();
714
- backend->cluster->execute(req, [barrier](couchbase::operations::touch_response resp) mutable { barrier->set_value(resp); });
715
- auto resp = f.get();
716
- if (resp.ec) {
717
- cb_raise_error_code(resp.ec, fmt::format("unable to touch {}", doc_id));
718
- }
831
+ auto barrier = std::make_shared<std::promise<couchbase::operations::touch_response>>();
832
+ auto f = barrier->get_future();
833
+ backend->cluster->execute(req, [barrier](couchbase::operations::touch_response resp) mutable { barrier->set_value(resp); });
834
+ auto resp = f.get();
835
+ if (resp.ec) {
836
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to touch {}", doc_id));
837
+ break;
838
+ }
719
839
 
720
- VALUE res = rb_hash_new();
721
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
722
- return res;
840
+ VALUE res = rb_hash_new();
841
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
842
+ return res;
843
+ } while (false);
844
+ rb_exc_raise(exc);
845
+ return Qnil;
723
846
  }
724
847
 
725
848
  static VALUE
726
- cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id)
849
+ cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout)
727
850
  {
728
851
  cb_backend_data* backend = nullptr;
729
852
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -736,46 +859,53 @@ cb_Backend_document_exists(VALUE self, VALUE bucket, VALUE collection, VALUE id)
736
859
  Check_Type(collection, T_STRING);
737
860
  Check_Type(id, T_STRING);
738
861
 
739
- couchbase::document_id doc_id;
740
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
741
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
742
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
862
+ VALUE exc = Qnil;
863
+ do {
864
+ couchbase::document_id doc_id;
865
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
866
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
867
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
743
868
 
744
- couchbase::operations::exists_request req{ doc_id };
745
-
746
- auto barrier = std::make_shared<std::promise<couchbase::operations::exists_response>>();
747
- auto f = barrier->get_future();
748
- backend->cluster->execute(req, [barrier](couchbase::operations::exists_response resp) mutable { barrier->set_value(resp); });
749
- auto resp = f.get();
750
- if (resp.ec) {
751
- cb_raise_error_code(resp.ec, fmt::format("unable to exists {}", doc_id));
752
- }
869
+ couchbase::operations::exists_request req{ doc_id };
870
+ cb__extract_timeout(req, timeout);
753
871
 
754
- VALUE res = rb_hash_new();
755
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
756
- rb_hash_aset(res, rb_id2sym(rb_intern("partition_id")), UINT2NUM(resp.partition_id));
757
- switch (resp.status) {
758
- case couchbase::operations::exists_response::observe_status::invalid:
759
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("invalid")));
760
- break;
761
- case couchbase::operations::exists_response::observe_status::found:
762
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("found")));
763
- break;
764
- case couchbase::operations::exists_response::observe_status::not_found:
765
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("not_found")));
766
- break;
767
- case couchbase::operations::exists_response::observe_status::persisted:
768
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("persisted")));
769
- break;
770
- case couchbase::operations::exists_response::observe_status::logically_deleted:
771
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("logically_deleted")));
872
+ auto barrier = std::make_shared<std::promise<couchbase::operations::exists_response>>();
873
+ auto f = barrier->get_future();
874
+ backend->cluster->execute(req, [barrier](couchbase::operations::exists_response resp) mutable { barrier->set_value(resp); });
875
+ auto resp = f.get();
876
+ if (resp.ec) {
877
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to exists {}", doc_id));
772
878
  break;
773
- }
774
- return res;
879
+ }
880
+
881
+ VALUE res = rb_hash_new();
882
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
883
+ rb_hash_aset(res, rb_id2sym(rb_intern("partition_id")), UINT2NUM(resp.partition_id));
884
+ switch (resp.status) {
885
+ case couchbase::operations::exists_response::observe_status::invalid:
886
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("invalid")));
887
+ break;
888
+ case couchbase::operations::exists_response::observe_status::found:
889
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("found")));
890
+ break;
891
+ case couchbase::operations::exists_response::observe_status::not_found:
892
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("not_found")));
893
+ break;
894
+ case couchbase::operations::exists_response::observe_status::persisted:
895
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("persisted")));
896
+ break;
897
+ case couchbase::operations::exists_response::observe_status::logically_deleted:
898
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_id2sym(rb_intern("logically_deleted")));
899
+ break;
900
+ }
901
+ return res;
902
+ } while (false);
903
+ rb_exc_raise(exc);
904
+ return Qnil;
775
905
  }
776
906
 
777
907
  static VALUE
778
- cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE cas)
908
+ cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE cas)
779
909
  {
780
910
  cb_backend_data* backend = nullptr;
781
911
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -788,36 +918,43 @@ cb_Backend_document_unlock(VALUE self, VALUE bucket, VALUE collection, VALUE id,
788
918
  Check_Type(collection, T_STRING);
789
919
  Check_Type(id, T_STRING);
790
920
 
791
- couchbase::document_id doc_id;
792
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
793
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
794
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
921
+ VALUE exc = Qnil;
922
+ do {
923
+ couchbase::document_id doc_id;
924
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
925
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
926
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
795
927
 
796
- couchbase::operations::unlock_request req{ doc_id };
797
- switch (TYPE(cas)) {
798
- case T_FIXNUM:
799
- case T_BIGNUM:
800
- req.cas = NUM2ULL(cas);
801
- break;
802
- default:
803
- rb_raise(rb_eArgError, "CAS must be an Integer");
804
- }
928
+ couchbase::operations::unlock_request req{ doc_id };
929
+ cb__extract_timeout(req, timeout);
930
+ switch (TYPE(cas)) {
931
+ case T_FIXNUM:
932
+ case T_BIGNUM:
933
+ req.cas = NUM2ULL(cas);
934
+ break;
935
+ default:
936
+ rb_raise(rb_eArgError, "CAS must be an Integer");
937
+ }
805
938
 
806
- auto barrier = std::make_shared<std::promise<couchbase::operations::unlock_response>>();
807
- auto f = barrier->get_future();
808
- backend->cluster->execute(req, [barrier](couchbase::operations::unlock_response resp) mutable { barrier->set_value(resp); });
809
- auto resp = f.get();
810
- if (resp.ec) {
811
- cb_raise_error_code(resp.ec, fmt::format("unable to unlock {}", doc_id));
812
- }
939
+ auto barrier = std::make_shared<std::promise<couchbase::operations::unlock_response>>();
940
+ auto f = barrier->get_future();
941
+ backend->cluster->execute(req, [barrier](couchbase::operations::unlock_response resp) mutable { barrier->set_value(resp); });
942
+ auto resp = f.get();
943
+ if (resp.ec) {
944
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to unlock {}", doc_id));
945
+ break;
946
+ }
813
947
 
814
- VALUE res = rb_hash_new();
815
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
816
- return res;
948
+ VALUE res = rb_hash_new();
949
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
950
+ return res;
951
+ } while (false);
952
+ rb_exc_raise(exc);
953
+ return Qnil;
817
954
  }
818
955
 
819
956
  static VALUE
820
- cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
957
+ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
821
958
  {
822
959
  cb_backend_data* backend = nullptr;
823
960
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -832,56 +969,63 @@ cb_Backend_document_upsert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
832
969
  Check_Type(content, T_STRING);
833
970
  Check_Type(flags, T_FIXNUM);
834
971
 
835
- couchbase::document_id doc_id;
836
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
837
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
838
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
839
- std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
840
-
841
- couchbase::operations::upsert_request req{ doc_id, value };
842
- req.flags = FIX2UINT(flags);
843
-
844
- if (!NIL_P(options)) {
845
- Check_Type(options, T_HASH);
846
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
847
- if (!NIL_P(durability_level)) {
848
- Check_Type(durability_level, T_SYMBOL);
849
- ID level = rb_sym2id(durability_level);
850
- if (level == rb_intern("none")) {
851
- req.durability_level = couchbase::protocol::durability_level::none;
852
- } else if (level == rb_intern("majority_and_persist_to_active")) {
853
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
854
- } else if (level == rb_intern("persist_to_majority")) {
855
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
856
- } else {
857
- rb_raise(rb_eArgError, "Unknown durability level");
972
+ VALUE exc = Qnil;
973
+ do {
974
+ couchbase::document_id doc_id;
975
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
976
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
977
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
978
+ std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
979
+
980
+ couchbase::operations::upsert_request req{ doc_id, value };
981
+ cb__extract_timeout(req, timeout);
982
+ req.flags = FIX2UINT(flags);
983
+
984
+ if (!NIL_P(options)) {
985
+ Check_Type(options, T_HASH);
986
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
987
+ if (!NIL_P(durability_level)) {
988
+ Check_Type(durability_level, T_SYMBOL);
989
+ ID level = rb_sym2id(durability_level);
990
+ if (level == rb_intern("none")) {
991
+ req.durability_level = couchbase::protocol::durability_level::none;
992
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
993
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
994
+ } else if (level == rb_intern("persist_to_majority")) {
995
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
996
+ } else {
997
+ rb_raise(rb_eArgError, "Unknown durability level");
998
+ }
999
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1000
+ if (!NIL_P(durability_timeout)) {
1001
+ Check_Type(durability_timeout, T_FIXNUM);
1002
+ req.durability_timeout = FIX2UINT(durability_timeout);
1003
+ }
858
1004
  }
859
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
860
- if (!NIL_P(durability_timeout)) {
861
- Check_Type(durability_timeout, T_FIXNUM);
862
- req.durability_timeout = FIX2UINT(durability_timeout);
1005
+ VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1006
+ if (!NIL_P(expiration)) {
1007
+ Check_Type(expiration, T_FIXNUM);
1008
+ req.expiration = FIX2UINT(expiration);
863
1009
  }
864
1010
  }
865
- VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
866
- if (!NIL_P(expiration)) {
867
- Check_Type(expiration, T_FIXNUM);
868
- req.expiration = FIX2UINT(expiration);
869
- }
870
- }
871
1011
 
872
- auto barrier = std::make_shared<std::promise<couchbase::operations::upsert_response>>();
873
- auto f = barrier->get_future();
874
- backend->cluster->execute(req, [barrier](couchbase::operations::upsert_response resp) mutable { barrier->set_value(resp); });
875
- auto resp = f.get();
876
- if (resp.ec) {
877
- cb_raise_error_code(resp.ec, fmt::format("unable to upsert {}", doc_id));
878
- }
1012
+ auto barrier = std::make_shared<std::promise<couchbase::operations::upsert_response>>();
1013
+ auto f = barrier->get_future();
1014
+ backend->cluster->execute(req, [barrier](couchbase::operations::upsert_response resp) mutable { barrier->set_value(resp); });
1015
+ auto resp = f.get();
1016
+ if (resp.ec) {
1017
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to upsert {}", doc_id));
1018
+ break;
1019
+ }
879
1020
 
880
- return cb__extract_mutation_result(resp);
1021
+ return cb__extract_mutation_result(resp);
1022
+ } while (false);
1023
+ rb_exc_raise(exc);
1024
+ return Qnil;
881
1025
  }
882
1026
 
883
1027
  static VALUE
884
- cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
1028
+ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
885
1029
  {
886
1030
  cb_backend_data* backend = nullptr;
887
1031
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -896,67 +1040,74 @@ cb_Backend_document_replace(VALUE self, VALUE bucket, VALUE collection, VALUE id
896
1040
  Check_Type(content, T_STRING);
897
1041
  Check_Type(flags, T_FIXNUM);
898
1042
 
899
- couchbase::document_id doc_id;
900
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
901
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
902
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
903
- std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
904
-
905
- couchbase::operations::replace_request req{ doc_id, value };
906
- req.flags = FIX2UINT(flags);
907
-
908
- if (!NIL_P(options)) {
909
- Check_Type(options, T_HASH);
910
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
911
- if (!NIL_P(durability_level)) {
912
- Check_Type(durability_level, T_SYMBOL);
913
- ID level = rb_sym2id(durability_level);
914
- if (level == rb_intern("none")) {
915
- req.durability_level = couchbase::protocol::durability_level::none;
916
- } else if (level == rb_intern("majority_and_persist_to_active")) {
917
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
918
- } else if (level == rb_intern("persist_to_majority")) {
919
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
920
- } else {
921
- rb_raise(rb_eArgError, "Unknown durability level");
1043
+ VALUE exc = Qnil;
1044
+ do {
1045
+ couchbase::document_id doc_id;
1046
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1047
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1048
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1049
+ std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1050
+
1051
+ couchbase::operations::replace_request req{ doc_id, value };
1052
+ cb__extract_timeout(req, timeout);
1053
+ req.flags = FIX2UINT(flags);
1054
+
1055
+ if (!NIL_P(options)) {
1056
+ Check_Type(options, T_HASH);
1057
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1058
+ if (!NIL_P(durability_level)) {
1059
+ Check_Type(durability_level, T_SYMBOL);
1060
+ ID level = rb_sym2id(durability_level);
1061
+ if (level == rb_intern("none")) {
1062
+ req.durability_level = couchbase::protocol::durability_level::none;
1063
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1064
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1065
+ } else if (level == rb_intern("persist_to_majority")) {
1066
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1067
+ } else {
1068
+ rb_raise(rb_eArgError, "Unknown durability level");
1069
+ }
1070
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1071
+ if (!NIL_P(durability_timeout)) {
1072
+ Check_Type(durability_timeout, T_FIXNUM);
1073
+ req.durability_timeout = FIX2UINT(durability_timeout);
1074
+ }
922
1075
  }
923
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
924
- if (!NIL_P(durability_timeout)) {
925
- Check_Type(durability_timeout, T_FIXNUM);
926
- req.durability_timeout = FIX2UINT(durability_timeout);
1076
+ VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1077
+ if (!NIL_P(expiration)) {
1078
+ Check_Type(expiration, T_FIXNUM);
1079
+ req.expiration = FIX2UINT(expiration);
927
1080
  }
928
- }
929
- VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
930
- if (!NIL_P(expiration)) {
931
- Check_Type(expiration, T_FIXNUM);
932
- req.expiration = FIX2UINT(expiration);
933
- }
934
- VALUE cas = rb_hash_aref(options, rb_id2sym(rb_intern("cas")));
935
- if (!NIL_P(cas)) {
936
- switch (TYPE(cas)) {
937
- case T_FIXNUM:
938
- case T_BIGNUM:
939
- req.cas = NUM2ULL(cas);
940
- break;
941
- default:
942
- rb_raise(rb_eArgError, "CAS must be an Integer");
1081
+ VALUE cas = rb_hash_aref(options, rb_id2sym(rb_intern("cas")));
1082
+ if (!NIL_P(cas)) {
1083
+ switch (TYPE(cas)) {
1084
+ case T_FIXNUM:
1085
+ case T_BIGNUM:
1086
+ req.cas = NUM2ULL(cas);
1087
+ break;
1088
+ default:
1089
+ rb_raise(rb_eArgError, "CAS must be an Integer");
1090
+ }
943
1091
  }
944
1092
  }
945
- }
946
1093
 
947
- auto barrier = std::make_shared<std::promise<couchbase::operations::replace_response>>();
948
- auto f = barrier->get_future();
949
- backend->cluster->execute(req, [barrier](couchbase::operations::replace_response resp) mutable { barrier->set_value(resp); });
950
- auto resp = f.get();
951
- if (resp.ec) {
952
- cb_raise_error_code(resp.ec, fmt::format("unable to replace {}", doc_id));
953
- }
1094
+ auto barrier = std::make_shared<std::promise<couchbase::operations::replace_response>>();
1095
+ auto f = barrier->get_future();
1096
+ backend->cluster->execute(req, [barrier](couchbase::operations::replace_response resp) mutable { barrier->set_value(resp); });
1097
+ auto resp = f.get();
1098
+ if (resp.ec) {
1099
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to replace {}", doc_id));
1100
+ break;
1101
+ }
954
1102
 
955
- return cb__extract_mutation_result(resp);
1103
+ return cb__extract_mutation_result(resp);
1104
+ } while (false);
1105
+ rb_exc_raise(exc);
1106
+ return Qnil;
956
1107
  }
957
1108
 
958
1109
  static VALUE
959
- cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE content, VALUE flags, VALUE options)
1110
+ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE content, VALUE flags, VALUE options)
960
1111
  {
961
1112
  cb_backend_data* backend = nullptr;
962
1113
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -971,56 +1122,63 @@ cb_Backend_document_insert(VALUE self, VALUE bucket, VALUE collection, VALUE id,
971
1122
  Check_Type(content, T_STRING);
972
1123
  Check_Type(flags, T_FIXNUM);
973
1124
 
974
- couchbase::document_id doc_id;
975
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
976
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
977
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
978
- std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
979
-
980
- couchbase::operations::insert_request req{ doc_id, value };
981
- req.flags = FIX2UINT(flags);
982
-
983
- if (!NIL_P(options)) {
984
- Check_Type(options, T_HASH);
985
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
986
- if (!NIL_P(durability_level)) {
987
- Check_Type(durability_level, T_SYMBOL);
988
- ID level = rb_sym2id(durability_level);
989
- if (level == rb_intern("none")) {
990
- req.durability_level = couchbase::protocol::durability_level::none;
991
- } else if (level == rb_intern("majority_and_persist_to_active")) {
992
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
993
- } else if (level == rb_intern("persist_to_majority")) {
994
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
995
- } else {
996
- rb_raise(rb_eArgError, "Unknown durability level");
1125
+ VALUE exc = Qnil;
1126
+ do {
1127
+ couchbase::document_id doc_id;
1128
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1129
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1130
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1131
+ std::string value(RSTRING_PTR(content), static_cast<size_t>(RSTRING_LEN(content)));
1132
+
1133
+ couchbase::operations::insert_request req{ doc_id, value };
1134
+ cb__extract_timeout(req, timeout);
1135
+ req.flags = FIX2UINT(flags);
1136
+
1137
+ if (!NIL_P(options)) {
1138
+ Check_Type(options, T_HASH);
1139
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1140
+ if (!NIL_P(durability_level)) {
1141
+ Check_Type(durability_level, T_SYMBOL);
1142
+ ID level = rb_sym2id(durability_level);
1143
+ if (level == rb_intern("none")) {
1144
+ req.durability_level = couchbase::protocol::durability_level::none;
1145
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1146
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1147
+ } else if (level == rb_intern("persist_to_majority")) {
1148
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1149
+ } else {
1150
+ rb_raise(rb_eArgError, "Unknown durability level");
1151
+ }
1152
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1153
+ if (!NIL_P(durability_timeout)) {
1154
+ Check_Type(durability_timeout, T_FIXNUM);
1155
+ req.durability_timeout = FIX2UINT(durability_timeout);
1156
+ }
997
1157
  }
998
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
999
- if (!NIL_P(durability_timeout)) {
1000
- Check_Type(durability_timeout, T_FIXNUM);
1001
- req.durability_timeout = FIX2UINT(durability_timeout);
1158
+ VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1159
+ if (!NIL_P(expiration)) {
1160
+ Check_Type(expiration, T_FIXNUM);
1161
+ req.expiration = FIX2UINT(expiration);
1002
1162
  }
1003
1163
  }
1004
- VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1005
- if (!NIL_P(expiration)) {
1006
- Check_Type(expiration, T_FIXNUM);
1007
- req.expiration = FIX2UINT(expiration);
1008
- }
1009
- }
1010
1164
 
1011
- auto barrier = std::make_shared<std::promise<couchbase::operations::insert_response>>();
1012
- auto f = barrier->get_future();
1013
- backend->cluster->execute(req, [barrier](couchbase::operations::insert_response resp) mutable { barrier->set_value(resp); });
1014
- auto resp = f.get();
1015
- if (resp.ec) {
1016
- cb_raise_error_code(resp.ec, fmt::format("unable to insert {}", doc_id));
1017
- }
1165
+ auto barrier = std::make_shared<std::promise<couchbase::operations::insert_response>>();
1166
+ auto f = barrier->get_future();
1167
+ backend->cluster->execute(req, [barrier](couchbase::operations::insert_response resp) mutable { barrier->set_value(resp); });
1168
+ auto resp = f.get();
1169
+ if (resp.ec) {
1170
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to insert {}", doc_id));
1171
+ break;
1172
+ }
1018
1173
 
1019
- return cb__extract_mutation_result(resp);
1174
+ return cb__extract_mutation_result(resp);
1175
+ } while (false);
1176
+ rb_exc_raise(exc);
1177
+ return Qnil;
1020
1178
  }
1021
1179
 
1022
1180
  static VALUE
1023
- cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1181
+ cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
1024
1182
  {
1025
1183
  cb_backend_data* backend = nullptr;
1026
1184
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1033,47 +1191,54 @@ cb_Backend_document_remove(VALUE self, VALUE bucket, VALUE collection, VALUE id,
1033
1191
  Check_Type(collection, T_STRING);
1034
1192
  Check_Type(id, T_STRING);
1035
1193
 
1036
- couchbase::document_id doc_id;
1037
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1038
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1039
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1040
-
1041
- couchbase::operations::remove_request req{ doc_id };
1042
- if (!NIL_P(options)) {
1043
- Check_Type(options, T_HASH);
1044
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1045
- if (!NIL_P(durability_level)) {
1046
- Check_Type(durability_level, T_SYMBOL);
1047
- ID level = rb_sym2id(durability_level);
1048
- if (level == rb_intern("none")) {
1049
- req.durability_level = couchbase::protocol::durability_level::none;
1050
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1051
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1052
- } else if (level == rb_intern("persist_to_majority")) {
1053
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1054
- } else {
1055
- rb_raise(rb_eArgError, "Unknown durability level");
1056
- }
1057
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1058
- if (!NIL_P(durability_timeout)) {
1059
- Check_Type(durability_timeout, T_FIXNUM);
1060
- req.durability_timeout = FIX2UINT(durability_timeout);
1194
+ VALUE exc = Qnil;
1195
+ do {
1196
+ couchbase::document_id doc_id;
1197
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1198
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1199
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1200
+
1201
+ couchbase::operations::remove_request req{ doc_id };
1202
+ cb__extract_timeout(req, timeout);
1203
+ if (!NIL_P(options)) {
1204
+ Check_Type(options, T_HASH);
1205
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1206
+ if (!NIL_P(durability_level)) {
1207
+ Check_Type(durability_level, T_SYMBOL);
1208
+ ID level = rb_sym2id(durability_level);
1209
+ if (level == rb_intern("none")) {
1210
+ req.durability_level = couchbase::protocol::durability_level::none;
1211
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1212
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1213
+ } else if (level == rb_intern("persist_to_majority")) {
1214
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1215
+ } else {
1216
+ rb_raise(rb_eArgError, "Unknown durability level");
1217
+ }
1218
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1219
+ if (!NIL_P(durability_timeout)) {
1220
+ Check_Type(durability_timeout, T_FIXNUM);
1221
+ req.durability_timeout = FIX2UINT(durability_timeout);
1222
+ }
1061
1223
  }
1062
1224
  }
1063
- }
1064
1225
 
1065
- auto barrier = std::make_shared<std::promise<couchbase::operations::remove_response>>();
1066
- auto f = barrier->get_future();
1067
- backend->cluster->execute(req, [barrier](couchbase::operations::remove_response resp) mutable { barrier->set_value(resp); });
1068
- auto resp = f.get();
1069
- if (resp.ec) {
1070
- cb_raise_error_code(resp.ec, fmt::format("unable to remove {}", doc_id));
1071
- }
1072
- return cb__extract_mutation_result(resp);
1226
+ auto barrier = std::make_shared<std::promise<couchbase::operations::remove_response>>();
1227
+ auto f = barrier->get_future();
1228
+ backend->cluster->execute(req, [barrier](couchbase::operations::remove_response resp) mutable { barrier->set_value(resp); });
1229
+ auto resp = f.get();
1230
+ if (resp.ec) {
1231
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to remove {}", doc_id));
1232
+ break;
1233
+ }
1234
+ return cb__extract_mutation_result(resp);
1235
+ } while (false);
1236
+ rb_exc_raise(exc);
1237
+ return Qnil;
1073
1238
  }
1074
1239
 
1075
1240
  static VALUE
1076
- cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1241
+ cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
1077
1242
  {
1078
1243
  cb_backend_data* backend = nullptr;
1079
1244
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1086,76 +1251,83 @@ cb_Backend_document_increment(VALUE self, VALUE bucket, VALUE collection, VALUE
1086
1251
  Check_Type(collection, T_STRING);
1087
1252
  Check_Type(id, T_STRING);
1088
1253
 
1089
- couchbase::document_id doc_id;
1090
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1091
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1092
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1093
-
1094
- couchbase::operations::increment_request req{ doc_id };
1095
- if (!NIL_P(options)) {
1096
- Check_Type(options, T_HASH);
1097
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1098
- if (!NIL_P(durability_level)) {
1099
- Check_Type(durability_level, T_SYMBOL);
1100
- ID level = rb_sym2id(durability_level);
1101
- if (level == rb_intern("none")) {
1102
- req.durability_level = couchbase::protocol::durability_level::none;
1103
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1104
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1105
- } else if (level == rb_intern("persist_to_majority")) {
1106
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1107
- } else {
1108
- rb_raise(rb_eArgError, "Unknown durability level");
1254
+ VALUE exc = Qnil;
1255
+ do {
1256
+ couchbase::document_id doc_id;
1257
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1258
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1259
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1260
+
1261
+ couchbase::operations::increment_request req{ doc_id };
1262
+ cb__extract_timeout(req, timeout);
1263
+ if (!NIL_P(options)) {
1264
+ Check_Type(options, T_HASH);
1265
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1266
+ if (!NIL_P(durability_level)) {
1267
+ Check_Type(durability_level, T_SYMBOL);
1268
+ ID level = rb_sym2id(durability_level);
1269
+ if (level == rb_intern("none")) {
1270
+ req.durability_level = couchbase::protocol::durability_level::none;
1271
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1272
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1273
+ } else if (level == rb_intern("persist_to_majority")) {
1274
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1275
+ } else {
1276
+ rb_raise(rb_eArgError, "Unknown durability level");
1277
+ }
1278
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1279
+ if (!NIL_P(durability_timeout)) {
1280
+ Check_Type(durability_timeout, T_FIXNUM);
1281
+ req.durability_timeout = FIX2UINT(durability_timeout);
1282
+ }
1109
1283
  }
1110
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1111
- if (!NIL_P(durability_timeout)) {
1112
- Check_Type(durability_timeout, T_FIXNUM);
1113
- req.durability_timeout = FIX2UINT(durability_timeout);
1284
+ VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1285
+ if (!NIL_P(delta)) {
1286
+ switch (TYPE(delta)) {
1287
+ case T_FIXNUM:
1288
+ case T_BIGNUM:
1289
+ req.delta = NUM2ULL(delta);
1290
+ break;
1291
+ default:
1292
+ rb_raise(rb_eArgError, "delta must be an Integer");
1293
+ }
1114
1294
  }
1115
- }
1116
- VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1117
- if (!NIL_P(delta)) {
1118
- switch (TYPE(delta)) {
1119
- case T_FIXNUM:
1120
- case T_BIGNUM:
1121
- req.delta = NUM2ULL(delta);
1122
- break;
1123
- default:
1124
- rb_raise(rb_eArgError, "delta must be an Integer");
1295
+ VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1296
+ if (!NIL_P(initial_value)) {
1297
+ switch (TYPE(initial_value)) {
1298
+ case T_FIXNUM:
1299
+ case T_BIGNUM:
1300
+ req.initial_value = NUM2ULL(initial_value);
1301
+ break;
1302
+ default:
1303
+ rb_raise(rb_eArgError, "initial_value must be an Integer");
1304
+ }
1125
1305
  }
1126
- }
1127
- VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1128
- if (!NIL_P(initial_value)) {
1129
- switch (TYPE(initial_value)) {
1130
- case T_FIXNUM:
1131
- case T_BIGNUM:
1132
- req.initial_value = NUM2ULL(initial_value);
1133
- break;
1134
- default:
1135
- rb_raise(rb_eArgError, "initial_value must be an Integer");
1306
+ VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1307
+ if (!NIL_P(expiration)) {
1308
+ Check_Type(expiration, T_FIXNUM);
1309
+ req.expiration = FIX2UINT(expiration);
1136
1310
  }
1137
1311
  }
1138
- VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1139
- if (!NIL_P(expiration)) {
1140
- Check_Type(expiration, T_FIXNUM);
1141
- req.expiration = FIX2UINT(expiration);
1142
- }
1143
- }
1144
1312
 
1145
- auto barrier = std::make_shared<std::promise<couchbase::operations::increment_response>>();
1146
- auto f = barrier->get_future();
1147
- backend->cluster->execute(req, [barrier](couchbase::operations::increment_response resp) mutable { barrier->set_value(resp); });
1148
- auto resp = f.get();
1149
- if (resp.ec) {
1150
- cb_raise_error_code(resp.ec, fmt::format("unable to increment {} by {}", doc_id, req.delta));
1151
- }
1152
- VALUE res = cb__extract_mutation_result(resp);
1153
- rb_hash_aset(res, rb_id2sym(rb_intern("content")), ULL2NUM(resp.content));
1154
- return res;
1313
+ auto barrier = std::make_shared<std::promise<couchbase::operations::increment_response>>();
1314
+ auto f = barrier->get_future();
1315
+ backend->cluster->execute(req, [barrier](couchbase::operations::increment_response resp) mutable { barrier->set_value(resp); });
1316
+ auto resp = f.get();
1317
+ if (resp.ec) {
1318
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to increment {} by {}", doc_id, req.delta));
1319
+ break;
1320
+ }
1321
+ VALUE res = cb__extract_mutation_result(resp);
1322
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), ULL2NUM(resp.content));
1323
+ return res;
1324
+ } while (false);
1325
+ rb_exc_raise(exc);
1326
+ return Qnil;
1155
1327
  }
1156
1328
 
1157
1329
  static VALUE
1158
- cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE options)
1330
+ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE options)
1159
1331
  {
1160
1332
  cb_backend_data* backend = nullptr;
1161
1333
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1169,72 +1341,79 @@ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE collection, VALUE
1169
1341
  Check_Type(id, T_STRING);
1170
1342
  Check_Type(options, T_HASH);
1171
1343
 
1172
- couchbase::document_id doc_id;
1173
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1174
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1175
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1176
-
1177
- couchbase::operations::decrement_request req{ doc_id };
1178
- if (!NIL_P(options)) {
1179
- Check_Type(options, T_HASH);
1180
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1181
- if (!NIL_P(durability_level)) {
1182
- Check_Type(durability_level, T_SYMBOL);
1183
- ID level = rb_sym2id(durability_level);
1184
- if (level == rb_intern("none")) {
1185
- req.durability_level = couchbase::protocol::durability_level::none;
1186
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1187
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1188
- } else if (level == rb_intern("persist_to_majority")) {
1189
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1190
- } else {
1191
- rb_raise(rb_eArgError, "Unknown durability level");
1344
+ VALUE exc = Qnil;
1345
+ do {
1346
+ couchbase::document_id doc_id;
1347
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1348
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1349
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1350
+
1351
+ couchbase::operations::decrement_request req{ doc_id };
1352
+ cb__extract_timeout(req, timeout);
1353
+ if (!NIL_P(options)) {
1354
+ Check_Type(options, T_HASH);
1355
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1356
+ if (!NIL_P(durability_level)) {
1357
+ Check_Type(durability_level, T_SYMBOL);
1358
+ ID level = rb_sym2id(durability_level);
1359
+ if (level == rb_intern("none")) {
1360
+ req.durability_level = couchbase::protocol::durability_level::none;
1361
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1362
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1363
+ } else if (level == rb_intern("persist_to_majority")) {
1364
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1365
+ } else {
1366
+ rb_raise(rb_eArgError, "Unknown durability level");
1367
+ }
1368
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1369
+ if (!NIL_P(durability_timeout)) {
1370
+ Check_Type(durability_timeout, T_FIXNUM);
1371
+ req.durability_timeout = FIX2UINT(durability_timeout);
1372
+ }
1192
1373
  }
1193
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1194
- if (!NIL_P(durability_timeout)) {
1195
- Check_Type(durability_timeout, T_FIXNUM);
1196
- req.durability_timeout = FIX2UINT(durability_timeout);
1374
+ VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1375
+ if (!NIL_P(delta)) {
1376
+ switch (TYPE(delta)) {
1377
+ case T_FIXNUM:
1378
+ case T_BIGNUM:
1379
+ req.delta = NUM2ULL(delta);
1380
+ break;
1381
+ default:
1382
+ rb_raise(rb_eArgError, "delta must be an Integer");
1383
+ }
1197
1384
  }
1198
- }
1199
- VALUE delta = rb_hash_aref(options, rb_id2sym(rb_intern("delta")));
1200
- if (!NIL_P(delta)) {
1201
- switch (TYPE(delta)) {
1202
- case T_FIXNUM:
1203
- case T_BIGNUM:
1204
- req.delta = NUM2ULL(delta);
1205
- break;
1206
- default:
1207
- rb_raise(rb_eArgError, "delta must be an Integer");
1385
+ VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1386
+ if (!NIL_P(initial_value)) {
1387
+ switch (TYPE(initial_value)) {
1388
+ case T_FIXNUM:
1389
+ case T_BIGNUM:
1390
+ req.initial_value = NUM2ULL(initial_value);
1391
+ break;
1392
+ default:
1393
+ rb_raise(rb_eArgError, "initial_value must be an Integer");
1394
+ }
1208
1395
  }
1209
- }
1210
- VALUE initial_value = rb_hash_aref(options, rb_id2sym(rb_intern("initial_value")));
1211
- if (!NIL_P(initial_value)) {
1212
- switch (TYPE(initial_value)) {
1213
- case T_FIXNUM:
1214
- case T_BIGNUM:
1215
- req.initial_value = NUM2ULL(initial_value);
1216
- break;
1217
- default:
1218
- rb_raise(rb_eArgError, "initial_value must be an Integer");
1396
+ VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1397
+ if (!NIL_P(expiration)) {
1398
+ Check_Type(expiration, T_FIXNUM);
1399
+ req.expiration = FIX2UINT(expiration);
1219
1400
  }
1220
1401
  }
1221
- VALUE expiration = rb_hash_aref(options, rb_id2sym(rb_intern("expiration")));
1222
- if (!NIL_P(expiration)) {
1223
- Check_Type(expiration, T_FIXNUM);
1224
- req.expiration = FIX2UINT(expiration);
1225
- }
1226
- }
1227
1402
 
1228
- auto barrier = std::make_shared<std::promise<couchbase::operations::decrement_response>>();
1229
- auto f = barrier->get_future();
1230
- backend->cluster->execute(req, [barrier](couchbase::operations::decrement_response resp) mutable { barrier->set_value(resp); });
1231
- auto resp = f.get();
1232
- if (resp.ec) {
1233
- cb_raise_error_code(resp.ec, fmt::format("unable to decrement {} by {}", doc_id, req.delta));
1234
- }
1235
- VALUE res = cb__extract_mutation_result(resp);
1236
- rb_hash_aset(res, rb_id2sym(rb_intern("content")), ULL2NUM(resp.content));
1237
- return res;
1403
+ auto barrier = std::make_shared<std::promise<couchbase::operations::decrement_response>>();
1404
+ auto f = barrier->get_future();
1405
+ backend->cluster->execute(req, [barrier](couchbase::operations::decrement_response resp) mutable { barrier->set_value(resp); });
1406
+ auto resp = f.get();
1407
+ if (resp.ec) {
1408
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to decrement {} by {}", doc_id, req.delta));
1409
+ break;
1410
+ }
1411
+ VALUE res = cb__extract_mutation_result(resp);
1412
+ rb_hash_aset(res, rb_id2sym(rb_intern("content")), ULL2NUM(resp.content));
1413
+ return res;
1414
+ } while (false);
1415
+ rb_exc_raise(exc);
1416
+ return Qnil;
1238
1417
  }
1239
1418
 
1240
1419
  static VALUE
@@ -1276,6 +1455,9 @@ cb__map_subdoc_opcode(couchbase::protocol::subdoc_opcode opcode)
1276
1455
 
1277
1456
  case couchbase::protocol::subdoc_opcode::get_count:
1278
1457
  return rb_id2sym(rb_intern("count"));
1458
+
1459
+ case couchbase::protocol::subdoc_opcode::get_doc:
1460
+ return rb_id2sym(rb_intern("get_doc"));
1279
1461
  }
1280
1462
  return rb_id2sym(rb_intern("unknown"));
1281
1463
  }
@@ -1338,7 +1520,7 @@ cb__map_subdoc_status(couchbase::protocol::status status)
1338
1520
  }
1339
1521
 
1340
1522
  static VALUE
1341
- cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE access_deleted, VALUE specs)
1523
+ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE timeout, VALUE access_deleted, VALUE specs)
1342
1524
  {
1343
1525
  cb_backend_data* backend = nullptr;
1344
1526
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1355,69 +1537,86 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1355
1537
  rb_raise(rb_eArgError, "Array with specs cannot be empty");
1356
1538
  }
1357
1539
 
1358
- couchbase::document_id doc_id;
1359
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1360
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1361
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1362
-
1363
- couchbase::operations::lookup_in_request req{ doc_id };
1364
- req.access_deleted = RTEST(access_deleted);
1365
- auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1366
- req.specs.entries.reserve(entries_size);
1367
- for (size_t i = 0; i < entries_size; ++i) {
1368
- VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
1369
- Check_Type(entry, T_HASH);
1370
- VALUE operation = rb_hash_aref(entry, rb_id2sym(rb_intern("opcode")));
1371
- Check_Type(operation, T_SYMBOL);
1372
- ID operation_id = rb_sym2id(operation);
1373
- couchbase::protocol::subdoc_opcode opcode;
1374
- if (operation_id == rb_intern("get") || operation_id == rb_intern("get_doc")) {
1375
- opcode = couchbase::protocol::subdoc_opcode::get;
1376
- } else if (operation_id == rb_intern("exists")) {
1377
- opcode = couchbase::protocol::subdoc_opcode::exists;
1378
- } else if (operation_id == rb_intern("count")) {
1379
- opcode = couchbase::protocol::subdoc_opcode::get_count;
1380
- } else {
1381
- rb_raise(rb_eArgError, "Unsupported operation for subdocument lookup");
1540
+ VALUE exc = Qnil;
1541
+ do {
1542
+ couchbase::document_id doc_id;
1543
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1544
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1545
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1546
+
1547
+ couchbase::operations::lookup_in_request req{ doc_id };
1548
+ cb__extract_timeout(req, timeout);
1549
+ req.access_deleted = RTEST(access_deleted);
1550
+ auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1551
+ req.specs.entries.reserve(entries_size);
1552
+ for (size_t i = 0; i < entries_size; ++i) {
1553
+ VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
1554
+ Check_Type(entry, T_HASH);
1555
+ VALUE operation = rb_hash_aref(entry, rb_id2sym(rb_intern("opcode")));
1556
+ Check_Type(operation, T_SYMBOL);
1557
+ ID operation_id = rb_sym2id(operation);
1558
+ couchbase::protocol::subdoc_opcode opcode;
1559
+ if (operation_id == rb_intern("get_doc")) {
1560
+ opcode = couchbase::protocol::subdoc_opcode::get_doc;
1561
+ } else if (operation_id == rb_intern("get")) {
1562
+ opcode = couchbase::protocol::subdoc_opcode::get;
1563
+ } else if (operation_id == rb_intern("exists")) {
1564
+ opcode = couchbase::protocol::subdoc_opcode::exists;
1565
+ } else if (operation_id == rb_intern("count")) {
1566
+ opcode = couchbase::protocol::subdoc_opcode::get_count;
1567
+ } else {
1568
+ rb_raise(rb_eArgError, "Unsupported operation for subdocument lookup");
1569
+ }
1570
+ bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
1571
+ VALUE path = rb_hash_aref(entry, rb_id2sym(rb_intern("path")));
1572
+ Check_Type(path, T_STRING);
1573
+ req.specs.add_spec(opcode, xattr, std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))));
1382
1574
  }
1383
- bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
1384
- VALUE path = rb_hash_aref(entry, rb_id2sym(rb_intern("path")));
1385
- Check_Type(path, T_STRING);
1386
- req.specs.add_spec(opcode, xattr, std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))));
1387
- }
1388
1575
 
1389
- auto barrier = std::make_shared<std::promise<couchbase::operations::lookup_in_response>>();
1390
- auto f = barrier->get_future();
1391
- backend->cluster->execute(req, [barrier](couchbase::operations::lookup_in_response resp) mutable { barrier->set_value(resp); });
1392
- auto resp = f.get();
1393
- if (resp.ec) {
1394
- cb_raise_error_code(resp.ec, fmt::format("unable fetch {}", doc_id));
1395
- }
1576
+ auto barrier = std::make_shared<std::promise<couchbase::operations::lookup_in_response>>();
1577
+ auto f = barrier->get_future();
1578
+ backend->cluster->execute(req, [barrier](couchbase::operations::lookup_in_response resp) mutable { barrier->set_value(resp); });
1579
+ auto resp = f.get();
1580
+ if (resp.ec) {
1581
+ exc = cb__map_error_code(resp.ec, fmt::format("unable fetch {}", doc_id));
1582
+ break;
1583
+ }
1396
1584
 
1397
- VALUE res = rb_hash_new();
1398
- rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
1399
- VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
1400
- rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
1401
- for (size_t i = 0; i < resp.fields.size(); ++i) {
1402
- VALUE entry = rb_hash_new();
1403
- rb_hash_aset(entry, rb_id2sym(rb_intern("exists")), resp.fields[i].exists ? Qtrue : Qfalse);
1404
- rb_hash_aset(
1405
- entry, rb_id2sym(rb_intern("path")), rb_str_new(resp.fields[i].path.data(), static_cast<long>(resp.fields[i].path.size())));
1406
- rb_hash_aset(
1407
- entry, rb_id2sym(rb_intern("value")), rb_str_new(resp.fields[i].value.data(), static_cast<long>(resp.fields[i].value.size())));
1408
- rb_hash_aset(entry, rb_id2sym(rb_intern("status")), cb__map_subdoc_status(resp.fields[i].status));
1409
- if (resp.fields[i].opcode == couchbase::protocol::subdoc_opcode::get && resp.fields[i].path.empty()) {
1410
- rb_hash_aset(entry, rb_id2sym(rb_intern("type")), rb_id2sym(rb_intern("get_doc")));
1411
- } else {
1412
- rb_hash_aset(entry, rb_id2sym(rb_intern("type")), cb__map_subdoc_opcode(resp.fields[i].opcode));
1585
+ VALUE res = rb_hash_new();
1586
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), ULL2NUM(resp.cas));
1587
+ VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
1588
+ rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
1589
+ for (size_t i = 0; i < resp.fields.size(); ++i) {
1590
+ VALUE entry = rb_hash_new();
1591
+ rb_hash_aset(entry, rb_id2sym(rb_intern("exists")), resp.fields[i].exists ? Qtrue : Qfalse);
1592
+ rb_hash_aset(
1593
+ entry, rb_id2sym(rb_intern("path")), rb_str_new(resp.fields[i].path.data(), static_cast<long>(resp.fields[i].path.size())));
1594
+ rb_hash_aset(entry,
1595
+ rb_id2sym(rb_intern("value")),
1596
+ rb_str_new(resp.fields[i].value.data(), static_cast<long>(resp.fields[i].value.size())));
1597
+ rb_hash_aset(entry, rb_id2sym(rb_intern("status")), cb__map_subdoc_status(resp.fields[i].status));
1598
+ if (resp.fields[i].opcode == couchbase::protocol::subdoc_opcode::get && resp.fields[i].path.empty()) {
1599
+ rb_hash_aset(entry, rb_id2sym(rb_intern("type")), rb_id2sym(rb_intern("get_doc")));
1600
+ } else {
1601
+ rb_hash_aset(entry, rb_id2sym(rb_intern("type")), cb__map_subdoc_opcode(resp.fields[i].opcode));
1602
+ }
1603
+ rb_ary_store(fields, static_cast<long>(i), entry);
1413
1604
  }
1414
- rb_ary_store(fields, static_cast<long>(i), entry);
1415
- }
1416
- return res;
1605
+ return res;
1606
+ } while (false);
1607
+ rb_exc_raise(exc);
1608
+ return Qnil;
1417
1609
  }
1418
1610
 
1419
1611
  static VALUE
1420
- cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE id, VALUE access_deleted, VALUE specs, VALUE options)
1612
+ cb_Backend_document_mutate_in(VALUE self,
1613
+ VALUE bucket,
1614
+ VALUE collection,
1615
+ VALUE id,
1616
+ VALUE timeout,
1617
+ VALUE access_deleted,
1618
+ VALUE specs,
1619
+ VALUE options)
1421
1620
  {
1422
1621
  cb_backend_data* backend = nullptr;
1423
1622
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1434,122 +1633,129 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE collection, VALUE
1434
1633
  rb_raise(rb_eArgError, "Array with specs cannot be empty");
1435
1634
  }
1436
1635
 
1437
- couchbase::document_id doc_id;
1438
- doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1439
- doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1440
- doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1441
-
1442
- couchbase::operations::mutate_in_request req{ doc_id };
1443
- if (!NIL_P(options)) {
1444
- Check_Type(options, T_HASH);
1445
- VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1446
- if (!NIL_P(durability_level)) {
1447
- Check_Type(durability_level, T_SYMBOL);
1448
- ID level = rb_sym2id(durability_level);
1449
- if (level == rb_intern("none")) {
1450
- req.durability_level = couchbase::protocol::durability_level::none;
1451
- } else if (level == rb_intern("majority_and_persist_to_active")) {
1452
- req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1453
- } else if (level == rb_intern("persist_to_majority")) {
1454
- req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1636
+ VALUE exc = Qnil;
1637
+ do {
1638
+ couchbase::document_id doc_id;
1639
+ doc_id.bucket.assign(RSTRING_PTR(bucket), static_cast<size_t>(RSTRING_LEN(bucket)));
1640
+ doc_id.collection.assign(RSTRING_PTR(collection), static_cast<size_t>(RSTRING_LEN(collection)));
1641
+ doc_id.key.assign(RSTRING_PTR(id), static_cast<size_t>(RSTRING_LEN(id)));
1642
+
1643
+ couchbase::operations::mutate_in_request req{ doc_id };
1644
+ cb__extract_timeout(req, timeout);
1645
+ if (!NIL_P(options)) {
1646
+ Check_Type(options, T_HASH);
1647
+ VALUE durability_level = rb_hash_aref(options, rb_id2sym(rb_intern("durability_level")));
1648
+ if (!NIL_P(durability_level)) {
1649
+ Check_Type(durability_level, T_SYMBOL);
1650
+ ID level = rb_sym2id(durability_level);
1651
+ if (level == rb_intern("none")) {
1652
+ req.durability_level = couchbase::protocol::durability_level::none;
1653
+ } else if (level == rb_intern("majority_and_persist_to_active")) {
1654
+ req.durability_level = couchbase::protocol::durability_level::majority_and_persist_to_active;
1655
+ } else if (level == rb_intern("persist_to_majority")) {
1656
+ req.durability_level = couchbase::protocol::durability_level::persist_to_majority;
1657
+ } else {
1658
+ rb_raise(rb_eArgError, "Unknown durability level");
1659
+ }
1660
+ VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1661
+ if (!NIL_P(durability_timeout)) {
1662
+ Check_Type(durability_timeout, T_FIXNUM);
1663
+ req.durability_timeout = FIX2UINT(durability_timeout);
1664
+ }
1665
+ }
1666
+ }
1667
+ req.access_deleted = RTEST(access_deleted);
1668
+ auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1669
+ req.specs.entries.reserve(entries_size);
1670
+ for (size_t i = 0; i < entries_size; ++i) {
1671
+ VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
1672
+ Check_Type(entry, T_HASH);
1673
+ VALUE operation = rb_hash_aref(entry, rb_id2sym(rb_intern("opcode")));
1674
+ Check_Type(operation, T_SYMBOL);
1675
+ ID operation_id = rb_sym2id(operation);
1676
+ couchbase::protocol::subdoc_opcode opcode;
1677
+ if (operation_id == rb_intern("dict_add")) {
1678
+ opcode = couchbase::protocol::subdoc_opcode::dict_add;
1679
+ } else if (operation_id == rb_intern("dict_upsert")) {
1680
+ opcode = couchbase::protocol::subdoc_opcode::dict_upsert;
1681
+ } else if (operation_id == rb_intern("remove")) {
1682
+ opcode = couchbase::protocol::subdoc_opcode::remove;
1683
+ } else if (operation_id == rb_intern("replace")) {
1684
+ opcode = couchbase::protocol::subdoc_opcode::replace;
1685
+ } else if (operation_id == rb_intern("array_push_last")) {
1686
+ opcode = couchbase::protocol::subdoc_opcode::array_push_last;
1687
+ } else if (operation_id == rb_intern("array_push_first")) {
1688
+ opcode = couchbase::protocol::subdoc_opcode::array_push_first;
1689
+ } else if (operation_id == rb_intern("array_insert")) {
1690
+ opcode = couchbase::protocol::subdoc_opcode::array_insert;
1691
+ } else if (operation_id == rb_intern("array_add_unique")) {
1692
+ opcode = couchbase::protocol::subdoc_opcode::array_add_unique;
1693
+ } else if (operation_id == rb_intern("counter")) {
1694
+ opcode = couchbase::protocol::subdoc_opcode::counter;
1455
1695
  } else {
1456
- rb_raise(rb_eArgError, "Unknown durability level");
1457
- }
1458
- VALUE durability_timeout = rb_hash_aref(options, rb_id2sym(rb_intern("durability_timeout")));
1459
- if (!NIL_P(durability_timeout)) {
1460
- Check_Type(durability_timeout, T_FIXNUM);
1461
- req.durability_timeout = FIX2UINT(durability_timeout);
1462
- }
1463
- }
1464
- }
1465
- req.access_deleted = RTEST(access_deleted);
1466
- auto entries_size = static_cast<size_t>(RARRAY_LEN(specs));
1467
- req.specs.entries.reserve(entries_size);
1468
- for (size_t i = 0; i < entries_size; ++i) {
1469
- VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
1470
- Check_Type(entry, T_HASH);
1471
- VALUE operation = rb_hash_aref(entry, rb_id2sym(rb_intern("opcode")));
1472
- Check_Type(operation, T_SYMBOL);
1473
- ID operation_id = rb_sym2id(operation);
1474
- couchbase::protocol::subdoc_opcode opcode;
1475
- if (operation_id == rb_intern("dict_add")) {
1476
- opcode = couchbase::protocol::subdoc_opcode::dict_add;
1477
- } else if (operation_id == rb_intern("dict_upsert")) {
1478
- opcode = couchbase::protocol::subdoc_opcode::dict_upsert;
1479
- } else if (operation_id == rb_intern("remove")) {
1480
- opcode = couchbase::protocol::subdoc_opcode::remove;
1481
- } else if (operation_id == rb_intern("replace")) {
1482
- opcode = couchbase::protocol::subdoc_opcode::replace;
1483
- } else if (operation_id == rb_intern("array_push_last")) {
1484
- opcode = couchbase::protocol::subdoc_opcode::array_push_last;
1485
- } else if (operation_id == rb_intern("array_push_first")) {
1486
- opcode = couchbase::protocol::subdoc_opcode::array_push_first;
1487
- } else if (operation_id == rb_intern("array_insert")) {
1488
- opcode = couchbase::protocol::subdoc_opcode::array_insert;
1489
- } else if (operation_id == rb_intern("array_add_unique")) {
1490
- opcode = couchbase::protocol::subdoc_opcode::array_add_unique;
1491
- } else if (operation_id == rb_intern("counter")) {
1492
- opcode = couchbase::protocol::subdoc_opcode::counter;
1493
- } else {
1494
- rb_raise(rb_eArgError, "Unsupported operation for subdocument mutation: %+" PRIsVALUE, operation);
1495
- }
1496
- bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
1497
- bool create_parents = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("create_parents"))));
1498
- bool expand_macros = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("expand_macros"))));
1499
- VALUE path = rb_hash_aref(entry, rb_id2sym(rb_intern("path")));
1500
- Check_Type(path, T_STRING);
1501
- VALUE param = rb_hash_aref(entry, rb_id2sym(rb_intern("param")));
1502
- if (NIL_P(param)) {
1503
- req.specs.add_spec(opcode, xattr, std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))));
1504
- } else if (opcode == couchbase::protocol::subdoc_opcode::counter) {
1505
- Check_Type(param, T_FIXNUM);
1506
- req.specs.add_spec(opcode,
1507
- xattr,
1508
- create_parents,
1509
- expand_macros,
1510
- std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))),
1511
- FIX2LONG(param));
1512
- } else {
1513
- Check_Type(param, T_STRING);
1514
- req.specs.add_spec(opcode,
1515
- xattr,
1516
- create_parents,
1517
- expand_macros,
1518
- std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))),
1519
- std::string(RSTRING_PTR(param), static_cast<size_t>(RSTRING_LEN(param))));
1696
+ rb_raise(rb_eArgError, "Unsupported operation for subdocument mutation: %+" PRIsVALUE, operation);
1697
+ }
1698
+ bool xattr = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("xattr"))));
1699
+ bool create_parents = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("create_parents"))));
1700
+ bool expand_macros = RTEST(rb_hash_aref(entry, rb_id2sym(rb_intern("expand_macros"))));
1701
+ VALUE path = rb_hash_aref(entry, rb_id2sym(rb_intern("path")));
1702
+ Check_Type(path, T_STRING);
1703
+ VALUE param = rb_hash_aref(entry, rb_id2sym(rb_intern("param")));
1704
+ if (NIL_P(param)) {
1705
+ req.specs.add_spec(opcode, xattr, std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))));
1706
+ } else if (opcode == couchbase::protocol::subdoc_opcode::counter) {
1707
+ Check_Type(param, T_FIXNUM);
1708
+ req.specs.add_spec(opcode,
1709
+ xattr,
1710
+ create_parents,
1711
+ expand_macros,
1712
+ std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))),
1713
+ FIX2LONG(param));
1714
+ } else {
1715
+ Check_Type(param, T_STRING);
1716
+ req.specs.add_spec(opcode,
1717
+ xattr,
1718
+ create_parents,
1719
+ expand_macros,
1720
+ std::string(RSTRING_PTR(path), static_cast<size_t>(RSTRING_LEN(path))),
1721
+ std::string(RSTRING_PTR(param), static_cast<size_t>(RSTRING_LEN(param))));
1722
+ }
1520
1723
  }
1521
- }
1522
1724
 
1523
- auto barrier = std::make_shared<std::promise<couchbase::operations::mutate_in_response>>();
1524
- auto f = barrier->get_future();
1525
- backend->cluster->execute(req, [barrier](couchbase::operations::mutate_in_response resp) mutable { barrier->set_value(resp); });
1526
- auto resp = f.get();
1527
- if (resp.ec) {
1528
- cb_raise_error_code(resp.ec, fmt::format("unable to mutate {}", doc_id));
1529
- }
1725
+ auto barrier = std::make_shared<std::promise<couchbase::operations::mutate_in_response>>();
1726
+ auto f = barrier->get_future();
1727
+ backend->cluster->execute(req, [barrier](couchbase::operations::mutate_in_response resp) mutable { barrier->set_value(resp); });
1728
+ auto resp = f.get();
1729
+ if (resp.ec) {
1730
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to mutate {}", doc_id));
1731
+ break;
1732
+ }
1530
1733
 
1531
- VALUE res = cb__extract_mutation_result(resp);
1532
- if (resp.first_error_index) {
1533
- rb_hash_aset(res, rb_id2sym(rb_intern("first_error_index")), ULONG2NUM(resp.first_error_index.value()));
1534
- }
1535
- VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
1536
- rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
1537
- for (size_t i = 0; i < resp.fields.size(); ++i) {
1538
- VALUE entry = rb_hash_new();
1539
- rb_hash_aset(
1540
- entry, rb_id2sym(rb_intern("path")), rb_str_new(resp.fields[i].path.data(), static_cast<long>(resp.fields[i].path.size())));
1541
- if (resp.fields[i].opcode == couchbase::protocol::subdoc_opcode::counter) {
1542
- rb_hash_aset(entry, rb_id2sym(rb_intern("value")), LONG2NUM(std::stoll(resp.fields[i].value)));
1543
- } else {
1544
- rb_hash_aset(entry,
1545
- rb_id2sym(rb_intern("value")),
1546
- rb_str_new(resp.fields[i].value.data(), static_cast<long>(resp.fields[i].value.size())));
1734
+ VALUE res = cb__extract_mutation_result(resp);
1735
+ if (resp.first_error_index) {
1736
+ rb_hash_aset(res, rb_id2sym(rb_intern("first_error_index")), ULONG2NUM(resp.first_error_index.value()));
1547
1737
  }
1548
- rb_hash_aset(entry, rb_id2sym(rb_intern("status")), cb__map_subdoc_status(resp.fields[i].status));
1549
- rb_hash_aset(entry, rb_id2sym(rb_intern("type")), cb__map_subdoc_opcode(resp.fields[i].opcode));
1550
- rb_ary_store(fields, static_cast<long>(i), entry);
1551
- }
1552
- return res;
1738
+ VALUE fields = rb_ary_new_capa(static_cast<long>(resp.fields.size()));
1739
+ rb_hash_aset(res, rb_id2sym(rb_intern("fields")), fields);
1740
+ for (size_t i = 0; i < resp.fields.size(); ++i) {
1741
+ VALUE entry = rb_hash_new();
1742
+ rb_hash_aset(
1743
+ entry, rb_id2sym(rb_intern("path")), rb_str_new(resp.fields[i].path.data(), static_cast<long>(resp.fields[i].path.size())));
1744
+ if (resp.fields[i].opcode == couchbase::protocol::subdoc_opcode::counter) {
1745
+ rb_hash_aset(entry, rb_id2sym(rb_intern("value")), LONG2NUM(std::stoll(resp.fields[i].value)));
1746
+ } else {
1747
+ rb_hash_aset(entry,
1748
+ rb_id2sym(rb_intern("value")),
1749
+ rb_str_new(resp.fields[i].value.data(), static_cast<long>(resp.fields[i].value.size())));
1750
+ }
1751
+ rb_hash_aset(entry, rb_id2sym(rb_intern("status")), cb__map_subdoc_status(resp.fields[i].status));
1752
+ rb_hash_aset(entry, rb_id2sym(rb_intern("type")), cb__map_subdoc_opcode(resp.fields[i].opcode));
1753
+ rb_ary_store(fields, static_cast<long>(i), entry);
1754
+ }
1755
+ return res;
1756
+ } while (false);
1757
+ rb_exc_raise(exc);
1758
+ return Qnil;
1553
1759
  }
1554
1760
 
1555
1761
  static int
@@ -1577,209 +1783,205 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
1577
1783
  Check_Type(statement, T_STRING);
1578
1784
  Check_Type(options, T_HASH);
1579
1785
 
1580
- couchbase::operations::query_request req;
1581
- req.statement.assign(RSTRING_PTR(statement), static_cast<size_t>(RSTRING_LEN(statement)));
1582
- VALUE client_context_id = rb_hash_aref(options, rb_id2sym(rb_intern("client_context_id")));
1583
- if (!NIL_P(client_context_id)) {
1584
- Check_Type(client_context_id, T_STRING);
1585
- req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
1586
- }
1587
- VALUE timeout = rb_hash_aref(options, rb_id2sym(rb_intern("timeout")));
1588
- if (!NIL_P(timeout)) {
1589
- switch (TYPE(timeout)) {
1590
- case T_FIXNUM:
1591
- case T_BIGNUM:
1592
- break;
1593
- default:
1594
- rb_raise(rb_eArgError, "timeout must be an Integer");
1786
+ VALUE exc = Qnil;
1787
+ do {
1788
+ couchbase::operations::query_request req;
1789
+ req.statement.assign(RSTRING_PTR(statement), static_cast<size_t>(RSTRING_LEN(statement)));
1790
+ VALUE client_context_id = rb_hash_aref(options, rb_id2sym(rb_intern("client_context_id")));
1791
+ if (!NIL_P(client_context_id)) {
1792
+ Check_Type(client_context_id, T_STRING);
1793
+ req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
1595
1794
  }
1596
- req.timeout = NUM2ULL(timeout);
1597
- }
1598
- VALUE adhoc = rb_hash_aref(options, rb_id2sym(rb_intern("adhoc")));
1599
- if (!NIL_P(adhoc)) {
1600
- req.adhoc = RTEST(adhoc);
1601
- }
1602
- VALUE metrics = rb_hash_aref(options, rb_id2sym(rb_intern("metrics")));
1603
- if (!NIL_P(metrics)) {
1604
- req.metrics = RTEST(metrics);
1605
- }
1606
- VALUE readonly = rb_hash_aref(options, rb_id2sym(rb_intern("readonly")));
1607
- if (!NIL_P(readonly)) {
1608
- req.readonly = RTEST(readonly);
1609
- }
1610
- VALUE scan_cap = rb_hash_aref(options, rb_id2sym(rb_intern("scan_cap")));
1611
- if (!NIL_P(scan_cap)) {
1612
- req.scan_cap = NUM2ULONG(scan_cap);
1613
- }
1614
- VALUE scan_wait = rb_hash_aref(options, rb_id2sym(rb_intern("scan_wait")));
1615
- if (!NIL_P(scan_wait)) {
1616
- req.scan_wait = NUM2ULONG(scan_wait);
1617
- }
1618
- VALUE max_parallelism = rb_hash_aref(options, rb_id2sym(rb_intern("max_parallelism")));
1619
- if (!NIL_P(max_parallelism)) {
1620
- req.max_parallelism = NUM2ULONG(max_parallelism);
1621
- }
1622
- VALUE pipeline_cap = rb_hash_aref(options, rb_id2sym(rb_intern("pipeline_cap")));
1623
- if (!NIL_P(pipeline_cap)) {
1624
- req.pipeline_cap = NUM2ULONG(pipeline_cap);
1625
- }
1626
- VALUE pipeline_batch = rb_hash_aref(options, rb_id2sym(rb_intern("pipeline_batch")));
1627
- if (!NIL_P(pipeline_batch)) {
1628
- req.pipeline_batch = NUM2ULONG(pipeline_batch);
1629
- }
1630
- VALUE profile = rb_hash_aref(options, rb_id2sym(rb_intern("profile")));
1631
- if (!NIL_P(profile)) {
1632
- Check_Type(profile, T_SYMBOL);
1633
- ID mode = rb_sym2id(profile);
1634
- if (mode == rb_intern("phases")) {
1635
- req.profile = couchbase::operations::query_request::profile_mode::phases;
1636
- } else if (mode == rb_intern("timings")) {
1637
- req.profile = couchbase::operations::query_request::profile_mode::timings;
1638
- } else if (mode == rb_intern("off")) {
1639
- req.profile = couchbase::operations::query_request::profile_mode::off;
1640
- }
1641
- }
1642
- VALUE positional_params = rb_hash_aref(options, rb_id2sym(rb_intern("positional_parameters")));
1643
- if (!NIL_P(positional_params)) {
1644
- Check_Type(positional_params, T_ARRAY);
1645
- auto entries_num = static_cast<size_t>(RARRAY_LEN(positional_params));
1646
- req.positional_parameters.reserve(entries_num);
1647
- for (size_t i = 0; i < entries_num; ++i) {
1648
- VALUE entry = rb_ary_entry(positional_params, static_cast<long>(i));
1649
- Check_Type(entry, T_STRING);
1650
- req.positional_parameters.emplace_back(
1651
- tao::json::from_string(std::string_view(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry)))));
1652
- }
1653
- }
1654
- VALUE named_params = rb_hash_aref(options, rb_id2sym(rb_intern("named_parameters")));
1655
- if (!NIL_P(named_params)) {
1656
- Check_Type(named_params, T_HASH);
1657
- rb_hash_foreach(named_params, INT_FUNC(cb__for_each_named_param), reinterpret_cast<VALUE>(&req));
1658
- }
1659
- VALUE scan_consistency = rb_hash_aref(options, rb_id2sym(rb_intern("scan_consistency")));
1660
- if (!NIL_P(scan_consistency)) {
1661
- Check_Type(scan_consistency, T_SYMBOL);
1662
- ID type = rb_sym2id(scan_consistency);
1663
- if (type == rb_intern("not_bounded")) {
1664
- req.scan_consistency = couchbase::operations::query_request::scan_consistency_type::not_bounded;
1665
- } else if (type == rb_intern("request_plus")) {
1666
- req.scan_consistency = couchbase::operations::query_request::scan_consistency_type::request_plus;
1667
- }
1668
- }
1669
- VALUE mutation_state = rb_hash_aref(options, rb_id2sym(rb_intern("mutation_state")));
1670
- if (!NIL_P(mutation_state)) {
1671
- Check_Type(mutation_state, T_ARRAY);
1672
- auto state_size = static_cast<size_t>(RARRAY_LEN(mutation_state));
1673
- req.mutation_state.reserve(state_size);
1674
- for (size_t i = 0; i < state_size; ++i) {
1675
- VALUE token = rb_ary_entry(mutation_state, static_cast<long>(i));
1676
- Check_Type(token, T_HASH);
1677
- VALUE bucket_name = rb_hash_aref(token, rb_id2sym(rb_intern("bucket_name")));
1678
- Check_Type(bucket_name, T_STRING);
1679
- VALUE partition_id = rb_hash_aref(token, rb_id2sym(rb_intern("partition_id")));
1680
- Check_Type(partition_id, T_FIXNUM);
1681
- VALUE partition_uuid = rb_hash_aref(token, rb_id2sym(rb_intern("partition_uuid")));
1682
- switch (TYPE(partition_uuid)) {
1683
- case T_FIXNUM:
1684
- case T_BIGNUM:
1685
- break;
1686
- default:
1687
- rb_raise(rb_eArgError, "partition_uuid must be an Integer");
1688
- }
1689
- VALUE sequence_number = rb_hash_aref(token, rb_id2sym(rb_intern("sequence_number")));
1690
- switch (TYPE(sequence_number)) {
1691
- case T_FIXNUM:
1692
- case T_BIGNUM:
1693
- break;
1694
- default:
1695
- rb_raise(rb_eArgError, "sequence_number must be an Integer");
1696
- }
1697
- req.mutation_state.emplace_back(
1698
- couchbase::mutation_token{ NUM2ULL(partition_uuid),
1699
- NUM2ULL(sequence_number),
1700
- gsl::narrow_cast<std::uint16_t>(NUM2UINT(partition_id)),
1701
- std::string(RSTRING_PTR(bucket_name), static_cast<std::size_t>(RSTRING_LEN(bucket_name))) });
1702
- }
1703
- }
1704
-
1705
- VALUE raw_params = rb_hash_aref(options, rb_id2sym(rb_intern("raw_parameters")));
1706
- if (!NIL_P(raw_params)) {
1707
- Check_Type(raw_params, T_HASH);
1708
- rb_hash_foreach(raw_params, INT_FUNC(cb__for_each_named_param), reinterpret_cast<VALUE>(&req));
1709
- }
1710
-
1711
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_response>>();
1712
- auto f = barrier->get_future();
1713
- backend->cluster->execute_http(req, [barrier](couchbase::operations::query_response resp) mutable { barrier->set_value(resp); });
1714
- auto resp = f.get();
1715
- if (resp.ec) {
1716
- if (resp.payload.meta_data.errors && !resp.payload.meta_data.errors->empty()) {
1717
- const auto& first_error = resp.payload.meta_data.errors->front();
1718
- cb_raise_error_code(resp.ec,
1719
- fmt::format("unable to query: \"{}{}\" ({}: {})",
1720
- req.statement.substr(0, 50),
1721
- req.statement.size() > 50 ? "..." : "",
1722
- first_error.code,
1723
- first_error.message));
1724
- } else {
1725
- cb_raise_error_code(
1726
- resp.ec, fmt::format("unable to query: \"{}{}\"", req.statement.substr(0, 50), req.statement.size() > 50 ? "..." : ""));
1795
+ cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
1796
+ VALUE adhoc = rb_hash_aref(options, rb_id2sym(rb_intern("adhoc")));
1797
+ if (!NIL_P(adhoc)) {
1798
+ req.adhoc = RTEST(adhoc);
1727
1799
  }
1728
- }
1729
- VALUE res = rb_hash_new();
1730
- VALUE rows = rb_ary_new_capa(static_cast<long>(resp.payload.rows.size()));
1731
- rb_hash_aset(res, rb_id2sym(rb_intern("rows")), rows);
1732
- for (auto& row : resp.payload.rows) {
1733
- rb_ary_push(rows, rb_str_new(row.data(), static_cast<long>(row.size())));
1734
- }
1735
- VALUE meta = rb_hash_new();
1736
- rb_hash_aset(res, rb_id2sym(rb_intern("meta")), meta);
1737
- rb_hash_aset(meta,
1738
- rb_id2sym(rb_intern("status")),
1739
- rb_id2sym(rb_intern2(resp.payload.meta_data.status.data(), static_cast<long>(resp.payload.meta_data.status.size()))));
1740
- rb_hash_aset(meta,
1741
- rb_id2sym(rb_intern("request_id")),
1742
- rb_str_new(resp.payload.meta_data.request_id.data(), static_cast<long>(resp.payload.meta_data.request_id.size())));
1743
- rb_hash_aset(
1744
- meta,
1745
- rb_id2sym(rb_intern("client_context_id")),
1746
- rb_str_new(resp.payload.meta_data.client_context_id.data(), static_cast<long>(resp.payload.meta_data.client_context_id.size())));
1747
- if (resp.payload.meta_data.signature) {
1800
+ VALUE metrics = rb_hash_aref(options, rb_id2sym(rb_intern("metrics")));
1801
+ if (!NIL_P(metrics)) {
1802
+ req.metrics = RTEST(metrics);
1803
+ }
1804
+ VALUE readonly = rb_hash_aref(options, rb_id2sym(rb_intern("readonly")));
1805
+ if (!NIL_P(readonly)) {
1806
+ req.readonly = RTEST(readonly);
1807
+ }
1808
+ VALUE scan_cap = rb_hash_aref(options, rb_id2sym(rb_intern("scan_cap")));
1809
+ if (!NIL_P(scan_cap)) {
1810
+ req.scan_cap = NUM2ULONG(scan_cap);
1811
+ }
1812
+ VALUE scan_wait = rb_hash_aref(options, rb_id2sym(rb_intern("scan_wait")));
1813
+ if (!NIL_P(scan_wait)) {
1814
+ req.scan_wait = NUM2ULONG(scan_wait);
1815
+ }
1816
+ VALUE max_parallelism = rb_hash_aref(options, rb_id2sym(rb_intern("max_parallelism")));
1817
+ if (!NIL_P(max_parallelism)) {
1818
+ req.max_parallelism = NUM2ULONG(max_parallelism);
1819
+ }
1820
+ VALUE pipeline_cap = rb_hash_aref(options, rb_id2sym(rb_intern("pipeline_cap")));
1821
+ if (!NIL_P(pipeline_cap)) {
1822
+ req.pipeline_cap = NUM2ULONG(pipeline_cap);
1823
+ }
1824
+ VALUE pipeline_batch = rb_hash_aref(options, rb_id2sym(rb_intern("pipeline_batch")));
1825
+ if (!NIL_P(pipeline_batch)) {
1826
+ req.pipeline_batch = NUM2ULONG(pipeline_batch);
1827
+ }
1828
+ VALUE profile = rb_hash_aref(options, rb_id2sym(rb_intern("profile")));
1829
+ if (!NIL_P(profile)) {
1830
+ Check_Type(profile, T_SYMBOL);
1831
+ ID mode = rb_sym2id(profile);
1832
+ if (mode == rb_intern("phases")) {
1833
+ req.profile = couchbase::operations::query_request::profile_mode::phases;
1834
+ } else if (mode == rb_intern("timings")) {
1835
+ req.profile = couchbase::operations::query_request::profile_mode::timings;
1836
+ } else if (mode == rb_intern("off")) {
1837
+ req.profile = couchbase::operations::query_request::profile_mode::off;
1838
+ }
1839
+ }
1840
+ VALUE positional_params = rb_hash_aref(options, rb_id2sym(rb_intern("positional_parameters")));
1841
+ if (!NIL_P(positional_params)) {
1842
+ Check_Type(positional_params, T_ARRAY);
1843
+ auto entries_num = static_cast<size_t>(RARRAY_LEN(positional_params));
1844
+ req.positional_parameters.reserve(entries_num);
1845
+ for (size_t i = 0; i < entries_num; ++i) {
1846
+ VALUE entry = rb_ary_entry(positional_params, static_cast<long>(i));
1847
+ Check_Type(entry, T_STRING);
1848
+ req.positional_parameters.emplace_back(
1849
+ tao::json::from_string(std::string_view(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry)))));
1850
+ }
1851
+ }
1852
+ VALUE named_params = rb_hash_aref(options, rb_id2sym(rb_intern("named_parameters")));
1853
+ if (!NIL_P(named_params)) {
1854
+ Check_Type(named_params, T_HASH);
1855
+ rb_hash_foreach(named_params, INT_FUNC(cb__for_each_named_param), reinterpret_cast<VALUE>(&req));
1856
+ }
1857
+ VALUE scan_consistency = rb_hash_aref(options, rb_id2sym(rb_intern("scan_consistency")));
1858
+ if (!NIL_P(scan_consistency)) {
1859
+ Check_Type(scan_consistency, T_SYMBOL);
1860
+ ID type = rb_sym2id(scan_consistency);
1861
+ if (type == rb_intern("not_bounded")) {
1862
+ req.scan_consistency = couchbase::operations::query_request::scan_consistency_type::not_bounded;
1863
+ } else if (type == rb_intern("request_plus")) {
1864
+ req.scan_consistency = couchbase::operations::query_request::scan_consistency_type::request_plus;
1865
+ }
1866
+ }
1867
+ VALUE mutation_state = rb_hash_aref(options, rb_id2sym(rb_intern("mutation_state")));
1868
+ if (!NIL_P(mutation_state)) {
1869
+ Check_Type(mutation_state, T_ARRAY);
1870
+ auto state_size = static_cast<size_t>(RARRAY_LEN(mutation_state));
1871
+ req.mutation_state.reserve(state_size);
1872
+ for (size_t i = 0; i < state_size; ++i) {
1873
+ VALUE token = rb_ary_entry(mutation_state, static_cast<long>(i));
1874
+ Check_Type(token, T_HASH);
1875
+ VALUE bucket_name = rb_hash_aref(token, rb_id2sym(rb_intern("bucket_name")));
1876
+ Check_Type(bucket_name, T_STRING);
1877
+ VALUE partition_id = rb_hash_aref(token, rb_id2sym(rb_intern("partition_id")));
1878
+ Check_Type(partition_id, T_FIXNUM);
1879
+ VALUE partition_uuid = rb_hash_aref(token, rb_id2sym(rb_intern("partition_uuid")));
1880
+ switch (TYPE(partition_uuid)) {
1881
+ case T_FIXNUM:
1882
+ case T_BIGNUM:
1883
+ break;
1884
+ default:
1885
+ rb_raise(rb_eArgError, "partition_uuid must be an Integer");
1886
+ }
1887
+ VALUE sequence_number = rb_hash_aref(token, rb_id2sym(rb_intern("sequence_number")));
1888
+ switch (TYPE(sequence_number)) {
1889
+ case T_FIXNUM:
1890
+ case T_BIGNUM:
1891
+ break;
1892
+ default:
1893
+ rb_raise(rb_eArgError, "sequence_number must be an Integer");
1894
+ }
1895
+ req.mutation_state.emplace_back(
1896
+ couchbase::mutation_token{ NUM2ULL(partition_uuid),
1897
+ NUM2ULL(sequence_number),
1898
+ gsl::narrow_cast<std::uint16_t>(NUM2UINT(partition_id)),
1899
+ std::string(RSTRING_PTR(bucket_name), static_cast<std::size_t>(RSTRING_LEN(bucket_name))) });
1900
+ }
1901
+ }
1902
+
1903
+ VALUE raw_params = rb_hash_aref(options, rb_id2sym(rb_intern("raw_parameters")));
1904
+ if (!NIL_P(raw_params)) {
1905
+ Check_Type(raw_params, T_HASH);
1906
+ rb_hash_foreach(raw_params, INT_FUNC(cb__for_each_named_param), reinterpret_cast<VALUE>(&req));
1907
+ }
1908
+
1909
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_response>>();
1910
+ auto f = barrier->get_future();
1911
+ backend->cluster->execute_http(req, [barrier](couchbase::operations::query_response resp) mutable { barrier->set_value(resp); });
1912
+ auto resp = f.get();
1913
+ if (resp.ec) {
1914
+ if (resp.payload.meta_data.errors && !resp.payload.meta_data.errors->empty()) {
1915
+ const auto& first_error = resp.payload.meta_data.errors->front();
1916
+ exc = cb__map_error_code(resp.ec,
1917
+ fmt::format("unable to query: \"{}{}\" ({}: {})",
1918
+ req.statement.substr(0, 50),
1919
+ req.statement.size() > 50 ? "..." : "",
1920
+ first_error.code,
1921
+ first_error.message));
1922
+ } else {
1923
+ exc = cb__map_error_code(
1924
+ resp.ec, fmt::format("unable to query: \"{}{}\"", req.statement.substr(0, 50), req.statement.size() > 50 ? "..." : ""));
1925
+ }
1926
+ break;
1927
+ }
1928
+ VALUE res = rb_hash_new();
1929
+ VALUE rows = rb_ary_new_capa(static_cast<long>(resp.payload.rows.size()));
1930
+ rb_hash_aset(res, rb_id2sym(rb_intern("rows")), rows);
1931
+ for (auto& row : resp.payload.rows) {
1932
+ rb_ary_push(rows, rb_str_new(row.data(), static_cast<long>(row.size())));
1933
+ }
1934
+ VALUE meta = rb_hash_new();
1935
+ rb_hash_aset(res, rb_id2sym(rb_intern("meta")), meta);
1748
1936
  rb_hash_aset(meta,
1749
- rb_id2sym(rb_intern("signature")),
1750
- rb_str_new(resp.payload.meta_data.signature->data(), static_cast<long>(resp.payload.meta_data.signature->size())));
1751
- }
1752
- if (resp.payload.meta_data.profile) {
1937
+ rb_id2sym(rb_intern("status")),
1938
+ rb_id2sym(rb_intern2(resp.payload.meta_data.status.data(), static_cast<long>(resp.payload.meta_data.status.size()))));
1753
1939
  rb_hash_aset(meta,
1754
- rb_id2sym(rb_intern("profile")),
1755
- rb_str_new(resp.payload.meta_data.profile->data(), static_cast<long>(resp.payload.meta_data.profile->size())));
1756
- }
1757
- metrics = rb_hash_new();
1758
- rb_hash_aset(meta, rb_id2sym(rb_intern("metrics")), metrics);
1759
- rb_hash_aset(metrics,
1760
- rb_id2sym(rb_intern("elapsed_time")),
1761
- rb_str_new(resp.payload.meta_data.metrics.elapsed_time.data(),
1762
- static_cast<long>(resp.payload.meta_data.metrics.elapsed_time.size())));
1763
- rb_hash_aset(metrics,
1764
- rb_id2sym(rb_intern("execution_time")),
1765
- rb_str_new(resp.payload.meta_data.metrics.execution_time.data(),
1766
- static_cast<long>(resp.payload.meta_data.metrics.execution_time.size())));
1767
- rb_hash_aset(metrics, rb_id2sym(rb_intern("result_count")), ULL2NUM(resp.payload.meta_data.metrics.result_count));
1768
- rb_hash_aset(metrics, rb_id2sym(rb_intern("result_size")), ULL2NUM(resp.payload.meta_data.metrics.result_count));
1769
- if (resp.payload.meta_data.metrics.sort_count) {
1770
- rb_hash_aset(metrics, rb_id2sym(rb_intern("sort_count")), ULL2NUM(*resp.payload.meta_data.metrics.sort_count));
1771
- }
1772
- if (resp.payload.meta_data.metrics.mutation_count) {
1773
- rb_hash_aset(metrics, rb_id2sym(rb_intern("mutation_count")), ULL2NUM(*resp.payload.meta_data.metrics.mutation_count));
1774
- }
1775
- if (resp.payload.meta_data.metrics.error_count) {
1776
- rb_hash_aset(metrics, rb_id2sym(rb_intern("error_count")), ULL2NUM(*resp.payload.meta_data.metrics.error_count));
1777
- }
1778
- if (resp.payload.meta_data.metrics.warning_count) {
1779
- rb_hash_aset(metrics, rb_id2sym(rb_intern("warning_count")), ULL2NUM(*resp.payload.meta_data.metrics.warning_count));
1780
- }
1940
+ rb_id2sym(rb_intern("request_id")),
1941
+ rb_str_new(resp.payload.meta_data.request_id.data(), static_cast<long>(resp.payload.meta_data.request_id.size())));
1942
+ rb_hash_aset(
1943
+ meta,
1944
+ rb_id2sym(rb_intern("client_context_id")),
1945
+ rb_str_new(resp.payload.meta_data.client_context_id.data(), static_cast<long>(resp.payload.meta_data.client_context_id.size())));
1946
+ if (resp.payload.meta_data.signature) {
1947
+ rb_hash_aset(meta,
1948
+ rb_id2sym(rb_intern("signature")),
1949
+ rb_str_new(resp.payload.meta_data.signature->data(), static_cast<long>(resp.payload.meta_data.signature->size())));
1950
+ }
1951
+ if (resp.payload.meta_data.profile) {
1952
+ rb_hash_aset(meta,
1953
+ rb_id2sym(rb_intern("profile")),
1954
+ rb_str_new(resp.payload.meta_data.profile->data(), static_cast<long>(resp.payload.meta_data.profile->size())));
1955
+ }
1956
+ metrics = rb_hash_new();
1957
+ rb_hash_aset(meta, rb_id2sym(rb_intern("metrics")), metrics);
1958
+ rb_hash_aset(metrics,
1959
+ rb_id2sym(rb_intern("elapsed_time")),
1960
+ rb_str_new(resp.payload.meta_data.metrics.elapsed_time.data(),
1961
+ static_cast<long>(resp.payload.meta_data.metrics.elapsed_time.size())));
1962
+ rb_hash_aset(metrics,
1963
+ rb_id2sym(rb_intern("execution_time")),
1964
+ rb_str_new(resp.payload.meta_data.metrics.execution_time.data(),
1965
+ static_cast<long>(resp.payload.meta_data.metrics.execution_time.size())));
1966
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("result_count")), ULL2NUM(resp.payload.meta_data.metrics.result_count));
1967
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("result_size")), ULL2NUM(resp.payload.meta_data.metrics.result_count));
1968
+ if (resp.payload.meta_data.metrics.sort_count) {
1969
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("sort_count")), ULL2NUM(*resp.payload.meta_data.metrics.sort_count));
1970
+ }
1971
+ if (resp.payload.meta_data.metrics.mutation_count) {
1972
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("mutation_count")), ULL2NUM(*resp.payload.meta_data.metrics.mutation_count));
1973
+ }
1974
+ if (resp.payload.meta_data.metrics.error_count) {
1975
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("error_count")), ULL2NUM(*resp.payload.meta_data.metrics.error_count));
1976
+ }
1977
+ if (resp.payload.meta_data.metrics.warning_count) {
1978
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("warning_count")), ULL2NUM(*resp.payload.meta_data.metrics.warning_count));
1979
+ }
1781
1980
 
1782
- return res;
1981
+ return res;
1982
+ } while (false);
1983
+ rb_exc_raise(exc);
1984
+ return Qnil;
1783
1985
  }
1784
1986
 
1785
1987
  static void
@@ -1878,7 +2080,7 @@ cb__generate_bucket_settings(VALUE bucket, couchbase::operations::bucket_setting
1878
2080
  }
1879
2081
 
1880
2082
  static VALUE
1881
- cb_Backend_bucket_create(VALUE self, VALUE bucket_settings)
2083
+ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings, VALUE timeout)
1882
2084
  {
1883
2085
  cb_backend_data* backend = nullptr;
1884
2086
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1888,23 +2090,31 @@ cb_Backend_bucket_create(VALUE self, VALUE bucket_settings)
1888
2090
  }
1889
2091
 
1890
2092
  Check_Type(bucket_settings, T_HASH);
1891
- couchbase::operations::bucket_create_request req{};
1892
- cb__generate_bucket_settings(bucket_settings, req.bucket, true);
1893
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_create_response>>();
1894
- auto f = barrier->get_future();
1895
- backend->cluster->execute_http(req,
1896
- [barrier](couchbase::operations::bucket_create_response resp) mutable { barrier->set_value(resp); });
1897
- auto resp = f.get();
1898
- if (resp.ec) {
1899
- cb_raise_error_code(resp.ec,
1900
- fmt::format("unable to create bucket \"{}\" on the cluster ({})", req.bucket.name, resp.error_message));
1901
- }
1902
2093
 
1903
- return Qtrue;
2094
+ VALUE exc = Qnil;
2095
+ do {
2096
+ couchbase::operations::bucket_create_request req{};
2097
+ cb__extract_timeout(req, timeout);
2098
+ cb__generate_bucket_settings(bucket_settings, req.bucket, true);
2099
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_create_response>>();
2100
+ auto f = barrier->get_future();
2101
+ backend->cluster->execute_http(req,
2102
+ [barrier](couchbase::operations::bucket_create_response resp) mutable { barrier->set_value(resp); });
2103
+ auto resp = f.get();
2104
+ if (resp.ec) {
2105
+ exc = cb__map_error_code(
2106
+ resp.ec, fmt::format("unable to create bucket \"{}\" on the cluster ({})", req.bucket.name, resp.error_message));
2107
+ break;
2108
+ }
2109
+
2110
+ return Qtrue;
2111
+ } while (false);
2112
+ rb_exc_raise(exc);
2113
+ return Qnil;
1904
2114
  }
1905
2115
 
1906
2116
  static VALUE
1907
- cb_Backend_bucket_update(VALUE self, VALUE bucket_settings)
2117
+ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings, VALUE timeout)
1908
2118
  {
1909
2119
  cb_backend_data* backend = nullptr;
1910
2120
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1914,23 +2124,29 @@ cb_Backend_bucket_update(VALUE self, VALUE bucket_settings)
1914
2124
  }
1915
2125
 
1916
2126
  Check_Type(bucket_settings, T_HASH);
1917
- couchbase::operations::bucket_update_request req{};
1918
- cb__generate_bucket_settings(bucket_settings, req.bucket, false);
1919
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_update_response>>();
1920
- auto f = barrier->get_future();
1921
- backend->cluster->execute_http(req,
1922
- [barrier](couchbase::operations::bucket_update_response resp) mutable { barrier->set_value(resp); });
1923
- auto resp = f.get();
1924
- if (resp.ec) {
1925
- cb_raise_error_code(resp.ec,
1926
- fmt::format("unable to update bucket \"{}\" on the cluster ({})", req.bucket.name, resp.error_message));
1927
- }
1928
-
1929
- return Qtrue;
2127
+ VALUE exc = Qnil;
2128
+ do {
2129
+ couchbase::operations::bucket_update_request req{};
2130
+ cb__extract_timeout(req, timeout);
2131
+ cb__generate_bucket_settings(bucket_settings, req.bucket, false);
2132
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_update_response>>();
2133
+ auto f = barrier->get_future();
2134
+ backend->cluster->execute_http(req,
2135
+ [barrier](couchbase::operations::bucket_update_response resp) mutable { barrier->set_value(resp); });
2136
+ auto resp = f.get();
2137
+ if (resp.ec) {
2138
+ exc = cb__map_error_code(
2139
+ resp.ec, fmt::format("unable to update bucket \"{}\" on the cluster ({})", req.bucket.name, resp.error_message));
2140
+ break;
2141
+ }
2142
+ return Qtrue;
2143
+ } while (false);
2144
+ rb_exc_raise(exc);
2145
+ return Qnil;
1930
2146
  }
1931
2147
 
1932
2148
  static VALUE
1933
- cb_Backend_bucket_drop(VALUE self, VALUE bucket_name)
2149
+ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name, VALUE timeout)
1934
2150
  {
1935
2151
  cb_backend_data* backend = nullptr;
1936
2152
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1941,21 +2157,28 @@ cb_Backend_bucket_drop(VALUE self, VALUE bucket_name)
1941
2157
 
1942
2158
  Check_Type(bucket_name, T_STRING);
1943
2159
 
1944
- couchbase::operations::bucket_drop_request req{};
1945
- req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
1946
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_drop_response>>();
1947
- auto f = barrier->get_future();
1948
- backend->cluster->execute_http(req, [barrier](couchbase::operations::bucket_drop_response resp) mutable { barrier->set_value(resp); });
1949
- auto resp = f.get();
1950
- if (resp.ec) {
1951
- cb_raise_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
1952
- }
1953
-
1954
- return Qtrue;
2160
+ VALUE exc = Qnil;
2161
+ do {
2162
+ couchbase::operations::bucket_drop_request req{};
2163
+ cb__extract_timeout(req, timeout);
2164
+ req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2165
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_drop_response>>();
2166
+ auto f = barrier->get_future();
2167
+ backend->cluster->execute_http(req,
2168
+ [barrier](couchbase::operations::bucket_drop_response resp) mutable { barrier->set_value(resp); });
2169
+ auto resp = f.get();
2170
+ if (resp.ec) {
2171
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
2172
+ break;
2173
+ }
2174
+ return Qtrue;
2175
+ } while (false);
2176
+ rb_exc_raise(exc);
2177
+ return Qnil;
1955
2178
  }
1956
2179
 
1957
2180
  static VALUE
1958
- cb_Backend_bucket_flush(VALUE self, VALUE bucket_name)
2181
+ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name, VALUE timeout)
1959
2182
  {
1960
2183
  cb_backend_data* backend = nullptr;
1961
2184
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -1966,17 +2189,25 @@ cb_Backend_bucket_flush(VALUE self, VALUE bucket_name)
1966
2189
 
1967
2190
  Check_Type(bucket_name, T_STRING);
1968
2191
 
1969
- couchbase::operations::bucket_flush_request req{};
1970
- req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
1971
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_flush_response>>();
1972
- auto f = barrier->get_future();
1973
- backend->cluster->execute_http(req, [barrier](couchbase::operations::bucket_flush_response resp) mutable { barrier->set_value(resp); });
1974
- auto resp = f.get();
1975
- if (resp.ec) {
1976
- cb_raise_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
1977
- }
2192
+ VALUE exc = Qnil;
2193
+ do {
2194
+ couchbase::operations::bucket_flush_request req{};
2195
+ cb__extract_timeout(req, timeout);
2196
+ req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2197
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_flush_response>>();
2198
+ auto f = barrier->get_future();
2199
+ backend->cluster->execute_http(req,
2200
+ [barrier](couchbase::operations::bucket_flush_response resp) mutable { barrier->set_value(resp); });
2201
+ auto resp = f.get();
2202
+ if (resp.ec) {
2203
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to remove bucket \"{}\" on the cluster", req.name));
2204
+ break;
2205
+ }
1978
2206
 
1979
- return Qtrue;
2207
+ return Qtrue;
2208
+ } while (false);
2209
+ rb_exc_raise(exc);
2210
+ return Qnil;
1980
2211
  }
1981
2212
 
1982
2213
  static void
@@ -2056,7 +2287,7 @@ cb__extract_bucket_settings(const couchbase::operations::bucket_settings& entry,
2056
2287
  }
2057
2288
 
2058
2289
  static VALUE
2059
- cb_Backend_bucket_get_all(VALUE self)
2290
+ cb_Backend_bucket_get_all(VALUE self, VALUE timeout)
2060
2291
  {
2061
2292
  cb_backend_data* backend = nullptr;
2062
2293
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2065,28 +2296,35 @@ cb_Backend_bucket_get_all(VALUE self)
2065
2296
  rb_raise(rb_eArgError, "Cluster has been closed already");
2066
2297
  }
2067
2298
 
2068
- couchbase::operations::bucket_get_all_request req{};
2069
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_all_response>>();
2070
- auto f = barrier->get_future();
2071
- backend->cluster->execute_http(req,
2072
- [barrier](couchbase::operations::bucket_get_all_response resp) mutable { barrier->set_value(resp); });
2073
- auto resp = f.get();
2074
- if (resp.ec) {
2075
- cb_raise_error_code(resp.ec, "unable to get list of the buckets of the cluster");
2076
- }
2299
+ VALUE exc = Qnil;
2300
+ do {
2301
+ couchbase::operations::bucket_get_all_request req{};
2302
+ cb__extract_timeout(req, timeout);
2303
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_all_response>>();
2304
+ auto f = barrier->get_future();
2305
+ backend->cluster->execute_http(
2306
+ req, [barrier](couchbase::operations::bucket_get_all_response resp) mutable { barrier->set_value(resp); });
2307
+ auto resp = f.get();
2308
+ if (resp.ec) {
2309
+ exc = cb__map_error_code(resp.ec, "unable to get list of the buckets of the cluster");
2310
+ break;
2311
+ }
2077
2312
 
2078
- VALUE res = rb_ary_new_capa(static_cast<long>(resp.buckets.size()));
2079
- for (const auto& entry : resp.buckets) {
2080
- VALUE bucket = rb_hash_new();
2081
- cb__extract_bucket_settings(entry, bucket);
2082
- rb_ary_push(res, bucket);
2083
- }
2313
+ VALUE res = rb_ary_new_capa(static_cast<long>(resp.buckets.size()));
2314
+ for (const auto& entry : resp.buckets) {
2315
+ VALUE bucket = rb_hash_new();
2316
+ cb__extract_bucket_settings(entry, bucket);
2317
+ rb_ary_push(res, bucket);
2318
+ }
2084
2319
 
2085
- return res;
2320
+ return res;
2321
+ } while (false);
2322
+ rb_exc_raise(exc);
2323
+ return Qnil;
2086
2324
  }
2087
2325
 
2088
2326
  static VALUE
2089
- cb_Backend_bucket_get(VALUE self, VALUE bucket_name)
2327
+ cb_Backend_bucket_get(VALUE self, VALUE bucket_name, VALUE timeout)
2090
2328
  {
2091
2329
  cb_backend_data* backend = nullptr;
2092
2330
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2097,20 +2335,28 @@ cb_Backend_bucket_get(VALUE self, VALUE bucket_name)
2097
2335
 
2098
2336
  Check_Type(bucket_name, T_STRING);
2099
2337
 
2100
- couchbase::operations::bucket_get_request req{};
2101
- req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2102
- auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_response>>();
2103
- auto f = barrier->get_future();
2104
- backend->cluster->execute_http(req, [barrier](couchbase::operations::bucket_get_response resp) mutable { barrier->set_value(resp); });
2105
- auto resp = f.get();
2106
- if (resp.ec) {
2107
- cb_raise_error_code(resp.ec, fmt::format("unable to locate bucket \"{}\" on the cluster", req.name));
2108
- }
2338
+ VALUE exc = Qnil;
2339
+ do {
2340
+ couchbase::operations::bucket_get_request req{};
2341
+ cb__extract_timeout(req, timeout);
2342
+ req.name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2343
+ auto barrier = std::make_shared<std::promise<couchbase::operations::bucket_get_response>>();
2344
+ auto f = barrier->get_future();
2345
+ backend->cluster->execute_http(req,
2346
+ [barrier](couchbase::operations::bucket_get_response resp) mutable { barrier->set_value(resp); });
2347
+ auto resp = f.get();
2348
+ if (resp.ec) {
2349
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to locate bucket \"{}\" on the cluster", req.name));
2350
+ break;
2351
+ }
2109
2352
 
2110
- VALUE res = rb_hash_new();
2111
- cb__extract_bucket_settings(resp.bucket, res);
2353
+ VALUE res = rb_hash_new();
2354
+ cb__extract_bucket_settings(resp.bucket, res);
2112
2355
 
2113
- return res;
2356
+ return res;
2357
+ } while (false);
2358
+ rb_exc_raise(exc);
2359
+ return Qnil;
2114
2360
  }
2115
2361
 
2116
2362
  static VALUE
@@ -2123,22 +2369,29 @@ cb_Backend_cluster_enable_developer_preview(VALUE self)
2123
2369
  rb_raise(rb_eArgError, "Cluster has been closed already");
2124
2370
  }
2125
2371
 
2126
- couchbase::operations::cluster_developer_preview_enable_request req{};
2127
- auto barrier = std::make_shared<std::promise<couchbase::operations::cluster_developer_preview_enable_response>>();
2128
- auto f = barrier->get_future();
2129
- backend->cluster->execute_http(
2130
- req, [barrier](couchbase::operations::cluster_developer_preview_enable_response resp) mutable { barrier->set_value(resp); });
2131
- auto resp = f.get();
2132
- if (resp.ec) {
2133
- cb_raise_error_code(resp.ec, fmt::format("unable to enable developer preview for this cluster"));
2134
- }
2135
- spdlog::critical("Developer preview cannot be disabled once it is enabled. If you enter developer preview mode you will not be able to "
2136
- "upgrade. DO NOT USE IN PRODUCTION.");
2137
- return Qtrue;
2372
+ VALUE exc = Qnil;
2373
+ do {
2374
+ couchbase::operations::cluster_developer_preview_enable_request req{};
2375
+ auto barrier = std::make_shared<std::promise<couchbase::operations::cluster_developer_preview_enable_response>>();
2376
+ auto f = barrier->get_future();
2377
+ backend->cluster->execute_http(
2378
+ req, [barrier](couchbase::operations::cluster_developer_preview_enable_response resp) mutable { barrier->set_value(resp); });
2379
+ auto resp = f.get();
2380
+ if (resp.ec) {
2381
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to enable developer preview for this cluster"));
2382
+ break;
2383
+ }
2384
+ spdlog::critical(
2385
+ "Developer preview cannot be disabled once it is enabled. If you enter developer preview mode you will not be able to "
2386
+ "upgrade. DO NOT USE IN PRODUCTION.");
2387
+ return Qtrue;
2388
+ } while (false);
2389
+ rb_exc_raise(exc);
2390
+ return Qnil;
2138
2391
  }
2139
2392
 
2140
2393
  static VALUE
2141
- cb_Backend_scope_get_all(VALUE self, VALUE bucket_name)
2394
+ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
2142
2395
  {
2143
2396
  cb_backend_data* backend = nullptr;
2144
2397
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2149,41 +2402,48 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name)
2149
2402
 
2150
2403
  Check_Type(bucket_name, T_STRING);
2151
2404
 
2152
- couchbase::operations::scope_get_all_request req{};
2153
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2154
- auto barrier = std::make_shared<std::promise<couchbase::operations::scope_get_all_response>>();
2155
- auto f = barrier->get_future();
2156
- backend->cluster->execute_http(req,
2157
- [barrier](couchbase::operations::scope_get_all_response resp) mutable { barrier->set_value(resp); });
2158
- auto resp = f.get();
2159
- if (resp.ec) {
2160
- cb_raise_error_code(resp.ec, fmt::format("unable to get list of the scopes of the bucket \"{}\"", req.bucket_name));
2161
- }
2405
+ VALUE exc = Qnil;
2406
+ do {
2407
+ couchbase::operations::scope_get_all_request req{};
2408
+ cb__extract_timeout(req, timeout);
2409
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2410
+ auto barrier = std::make_shared<std::promise<couchbase::operations::scope_get_all_response>>();
2411
+ auto f = barrier->get_future();
2412
+ backend->cluster->execute_http(req,
2413
+ [barrier](couchbase::operations::scope_get_all_response resp) mutable { barrier->set_value(resp); });
2414
+ auto resp = f.get();
2415
+ if (resp.ec) {
2416
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to get list of the scopes of the bucket \"{}\"", req.bucket_name));
2417
+ break;
2418
+ }
2162
2419
 
2163
- VALUE res = rb_hash_new();
2164
- rb_hash_aset(res, rb_id2sym(rb_intern("uid")), ULL2NUM(resp.manifest.uid));
2165
- VALUE scopes = rb_ary_new_capa(static_cast<long>(resp.manifest.scopes.size()));
2166
- for (const auto& s : resp.manifest.scopes) {
2167
- VALUE scope = rb_hash_new();
2168
- rb_hash_aset(scope, rb_id2sym(rb_intern("uid")), ULL2NUM(s.uid));
2169
- rb_hash_aset(scope, rb_id2sym(rb_intern("name")), rb_str_new(s.name.data(), static_cast<long>(s.name.size())));
2170
- VALUE collections = rb_ary_new_capa(static_cast<long>(s.collections.size()));
2171
- for (const auto& c : s.collections) {
2172
- VALUE collection = rb_hash_new();
2173
- rb_hash_aset(collection, rb_id2sym(rb_intern("uid")), ULL2NUM(c.uid));
2174
- rb_hash_aset(collection, rb_id2sym(rb_intern("name")), rb_str_new(c.name.data(), static_cast<long>(c.name.size())));
2175
- rb_ary_push(collections, collection);
2176
- }
2177
- rb_hash_aset(scope, rb_id2sym(rb_intern("collections")), collections);
2178
- rb_ary_push(scopes, scope);
2179
- }
2180
- rb_hash_aset(res, rb_id2sym(rb_intern("scopes")), scopes);
2420
+ VALUE res = rb_hash_new();
2421
+ rb_hash_aset(res, rb_id2sym(rb_intern("uid")), ULL2NUM(resp.manifest.uid));
2422
+ VALUE scopes = rb_ary_new_capa(static_cast<long>(resp.manifest.scopes.size()));
2423
+ for (const auto& s : resp.manifest.scopes) {
2424
+ VALUE scope = rb_hash_new();
2425
+ rb_hash_aset(scope, rb_id2sym(rb_intern("uid")), ULL2NUM(s.uid));
2426
+ rb_hash_aset(scope, rb_id2sym(rb_intern("name")), rb_str_new(s.name.data(), static_cast<long>(s.name.size())));
2427
+ VALUE collections = rb_ary_new_capa(static_cast<long>(s.collections.size()));
2428
+ for (const auto& c : s.collections) {
2429
+ VALUE collection = rb_hash_new();
2430
+ rb_hash_aset(collection, rb_id2sym(rb_intern("uid")), ULL2NUM(c.uid));
2431
+ rb_hash_aset(collection, rb_id2sym(rb_intern("name")), rb_str_new(c.name.data(), static_cast<long>(c.name.size())));
2432
+ rb_ary_push(collections, collection);
2433
+ }
2434
+ rb_hash_aset(scope, rb_id2sym(rb_intern("collections")), collections);
2435
+ rb_ary_push(scopes, scope);
2436
+ }
2437
+ rb_hash_aset(res, rb_id2sym(rb_intern("scopes")), scopes);
2181
2438
 
2182
- return res;
2439
+ return res;
2440
+ } while (false);
2441
+ rb_exc_raise(exc);
2442
+ return Qnil;
2183
2443
  }
2184
2444
 
2185
2445
  static VALUE
2186
- cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name)
2446
+ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE timeout)
2187
2447
  {
2188
2448
  cb_backend_data* backend = nullptr;
2189
2449
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2195,21 +2455,29 @@ cb_Backend_scope_create(VALUE self, VALUE bucket_name, VALUE scope_name)
2195
2455
  Check_Type(bucket_name, T_STRING);
2196
2456
  Check_Type(scope_name, T_STRING);
2197
2457
 
2198
- couchbase::operations::scope_create_request req{};
2199
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2200
- req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2201
- auto barrier = std::make_shared<std::promise<couchbase::operations::scope_create_response>>();
2202
- auto f = barrier->get_future();
2203
- backend->cluster->execute_http(req, [barrier](couchbase::operations::scope_create_response resp) mutable { barrier->set_value(resp); });
2204
- auto resp = f.get();
2205
- if (resp.ec) {
2206
- cb_raise_error_code(resp.ec, fmt::format("unable to create the scope on the bucket \"{}\"", req.bucket_name));
2207
- }
2208
- return ULL2NUM(resp.uid);
2458
+ VALUE exc = Qnil;
2459
+ do {
2460
+ couchbase::operations::scope_create_request req{};
2461
+ cb__extract_timeout(req, timeout);
2462
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2463
+ req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2464
+ auto barrier = std::make_shared<std::promise<couchbase::operations::scope_create_response>>();
2465
+ auto f = barrier->get_future();
2466
+ backend->cluster->execute_http(req,
2467
+ [barrier](couchbase::operations::scope_create_response resp) mutable { barrier->set_value(resp); });
2468
+ auto resp = f.get();
2469
+ if (resp.ec) {
2470
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to create the scope on the bucket \"{}\"", req.bucket_name));
2471
+ break;
2472
+ }
2473
+ return ULL2NUM(resp.uid);
2474
+ } while (false);
2475
+ rb_exc_raise(exc);
2476
+ return Qnil;
2209
2477
  }
2210
2478
 
2211
2479
  static VALUE
2212
- cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name)
2480
+ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE timeout)
2213
2481
  {
2214
2482
  cb_backend_data* backend = nullptr;
2215
2483
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2221,21 +2489,30 @@ cb_Backend_scope_drop(VALUE self, VALUE bucket_name, VALUE scope_name)
2221
2489
  Check_Type(bucket_name, T_STRING);
2222
2490
  Check_Type(scope_name, T_STRING);
2223
2491
 
2224
- couchbase::operations::scope_drop_request req{};
2225
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2226
- req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2227
- auto barrier = std::make_shared<std::promise<couchbase::operations::scope_drop_response>>();
2228
- auto f = barrier->get_future();
2229
- backend->cluster->execute_http(req, [barrier](couchbase::operations::scope_drop_response resp) mutable { barrier->set_value(resp); });
2230
- auto resp = f.get();
2231
- if (resp.ec) {
2232
- cb_raise_error_code(resp.ec, fmt::format("unable to drop the scope \"{}\" on the bucket \"{}\"", req.scope_name, req.bucket_name));
2233
- }
2234
- return ULL2NUM(resp.uid);
2492
+ VALUE exc = Qnil;
2493
+ do {
2494
+ couchbase::operations::scope_drop_request req{};
2495
+ cb__extract_timeout(req, timeout);
2496
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2497
+ req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2498
+ auto barrier = std::make_shared<std::promise<couchbase::operations::scope_drop_response>>();
2499
+ auto f = barrier->get_future();
2500
+ backend->cluster->execute_http(req,
2501
+ [barrier](couchbase::operations::scope_drop_response resp) mutable { barrier->set_value(resp); });
2502
+ auto resp = f.get();
2503
+ if (resp.ec) {
2504
+ exc = cb__map_error_code(resp.ec,
2505
+ fmt::format("unable to drop the scope \"{}\" on the bucket \"{}\"", req.scope_name, req.bucket_name));
2506
+ break;
2507
+ }
2508
+ return ULL2NUM(resp.uid);
2509
+ } while (false);
2510
+ rb_exc_raise(exc);
2511
+ return Qnil;
2235
2512
  }
2236
2513
 
2237
2514
  static VALUE
2238
- cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE max_expiry)
2515
+ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE max_expiry, VALUE timeout)
2239
2516
  {
2240
2517
  cb_backend_data* backend = nullptr;
2241
2518
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2248,28 +2525,38 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
2248
2525
  Check_Type(scope_name, T_STRING);
2249
2526
  Check_Type(collection_name, T_STRING);
2250
2527
 
2251
- couchbase::operations::collection_create_request req{};
2252
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2253
- req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2254
- req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
2255
-
2256
- if (!NIL_P(max_expiry)) {
2257
- Check_Type(max_expiry, T_FIXNUM);
2258
- req.max_expiry = FIX2UINT(max_expiry);
2259
- }
2260
- auto barrier = std::make_shared<std::promise<couchbase::operations::collection_create_response>>();
2261
- auto f = barrier->get_future();
2262
- backend->cluster->execute_http(req,
2263
- [barrier](couchbase::operations::collection_create_response resp) mutable { barrier->set_value(resp); });
2264
- auto resp = f.get();
2265
- if (resp.ec) {
2266
- cb_raise_error_code(resp.ec, fmt::format("unable to create the collection on the bucket \"{}\"", req.bucket_name));
2267
- }
2268
- return ULL2NUM(resp.uid);
2528
+ VALUE exc = Qnil;
2529
+ do {
2530
+ couchbase::operations::collection_create_request req{};
2531
+ cb__extract_timeout(req, timeout);
2532
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2533
+ req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2534
+ req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
2535
+
2536
+ if (!NIL_P(max_expiry)) {
2537
+ Check_Type(max_expiry, T_FIXNUM);
2538
+ req.max_expiry = FIX2UINT(max_expiry);
2539
+ }
2540
+ auto barrier = std::make_shared<std::promise<couchbase::operations::collection_create_response>>();
2541
+ auto f = barrier->get_future();
2542
+ backend->cluster->execute_http(
2543
+ req, [barrier](couchbase::operations::collection_create_response resp) mutable { barrier->set_value(resp); });
2544
+ auto resp = f.get();
2545
+ if (resp.ec) {
2546
+ exc = cb__map_error_code(
2547
+ resp.ec,
2548
+ fmt::format(
2549
+ R"(unable create the collection "{}.{}" on the bucket "{}")", req.scope_name, req.collection_name, req.bucket_name));
2550
+ break;
2551
+ }
2552
+ return ULL2NUM(resp.uid);
2553
+ } while (false);
2554
+ rb_exc_raise(exc);
2555
+ return Qnil;
2269
2556
  }
2270
2557
 
2271
2558
  static VALUE
2272
- cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name)
2559
+ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALUE collection_name, VALUE timeout)
2273
2560
  {
2274
2561
  cb_backend_data* backend = nullptr;
2275
2562
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2282,27 +2569,34 @@ cb_Backend_collection_drop(VALUE self, VALUE bucket_name, VALUE scope_name, VALU
2282
2569
  Check_Type(scope_name, T_STRING);
2283
2570
  Check_Type(collection_name, T_STRING);
2284
2571
 
2285
- couchbase::operations::collection_drop_request req{};
2286
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2287
- req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2288
- req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
2572
+ VALUE exc = Qnil;
2573
+ do {
2574
+ couchbase::operations::collection_drop_request req{};
2575
+ cb__extract_timeout(req, timeout);
2576
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2577
+ req.scope_name.assign(RSTRING_PTR(scope_name), static_cast<size_t>(RSTRING_LEN(scope_name)));
2578
+ req.collection_name.assign(RSTRING_PTR(collection_name), static_cast<size_t>(RSTRING_LEN(collection_name)));
2289
2579
 
2290
- auto barrier = std::make_shared<std::promise<couchbase::operations::collection_drop_response>>();
2291
- auto f = barrier->get_future();
2292
- backend->cluster->execute_http(req,
2293
- [barrier](couchbase::operations::collection_drop_response resp) mutable { barrier->set_value(resp); });
2294
- auto resp = f.get();
2295
- if (resp.ec) {
2296
- cb_raise_error_code(
2297
- resp.ec,
2298
- fmt::format(
2299
- R"(unable to drop the collection "{}.{}" on the bucket "{}")", req.scope_name, req.collection_name, req.bucket_name));
2300
- }
2301
- return ULL2NUM(resp.uid);
2580
+ auto barrier = std::make_shared<std::promise<couchbase::operations::collection_drop_response>>();
2581
+ auto f = barrier->get_future();
2582
+ backend->cluster->execute_http(
2583
+ req, [barrier](couchbase::operations::collection_drop_response resp) mutable { barrier->set_value(resp); });
2584
+ auto resp = f.get();
2585
+ if (resp.ec) {
2586
+ exc = cb__map_error_code(
2587
+ resp.ec,
2588
+ fmt::format(
2589
+ R"(unable to drop the collection "{}.{}" on the bucket "{}")", req.scope_name, req.collection_name, req.bucket_name));
2590
+ break;
2591
+ }
2592
+ return ULL2NUM(resp.uid);
2593
+ } while (false);
2594
+ rb_exc_raise(exc);
2595
+ return Qnil;
2302
2596
  }
2303
2597
 
2304
2598
  static VALUE
2305
- cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name)
2599
+ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE timeout)
2306
2600
  {
2307
2601
  cb_backend_data* backend = nullptr;
2308
2602
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2313,52 +2607,59 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name)
2313
2607
 
2314
2608
  Check_Type(bucket_name, T_STRING);
2315
2609
 
2316
- couchbase::operations::query_index_get_all_request req{};
2317
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2318
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_get_all_response>>();
2319
- auto f = barrier->get_future();
2320
- backend->cluster->execute_http(
2321
- req, [barrier](couchbase::operations::query_index_get_all_response resp) mutable { barrier->set_value(resp); });
2322
- auto resp = f.get();
2323
- if (resp.ec) {
2324
- cb_raise_error_code(resp.ec, fmt::format("unable to get list of the indexes of the bucket \"{}\"", req.bucket_name));
2325
- }
2610
+ VALUE exc = Qnil;
2611
+ do {
2612
+ couchbase::operations::query_index_get_all_request req{};
2613
+ cb__extract_timeout(req, timeout);
2614
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2615
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_get_all_response>>();
2616
+ auto f = barrier->get_future();
2617
+ backend->cluster->execute_http(
2618
+ req, [barrier](couchbase::operations::query_index_get_all_response resp) mutable { barrier->set_value(resp); });
2619
+ auto resp = f.get();
2620
+ if (resp.ec) {
2621
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to get list of the indexes of the bucket \"{}\"", req.bucket_name));
2622
+ break;
2623
+ }
2326
2624
 
2327
- VALUE res = rb_hash_new();
2328
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2329
- VALUE indexes = rb_ary_new_capa(static_cast<long>(resp.indexes.size()));
2330
- for (const auto& idx : resp.indexes) {
2331
- VALUE index = rb_hash_new();
2332
- rb_hash_aset(index, rb_id2sym(rb_intern("id")), rb_str_new(idx.id.data(), static_cast<long>(idx.id.size())));
2333
- rb_hash_aset(index, rb_id2sym(rb_intern("state")), rb_str_new(idx.state.data(), static_cast<long>(idx.state.size())));
2334
- rb_hash_aset(index, rb_id2sym(rb_intern("name")), rb_str_new(idx.name.data(), static_cast<long>(idx.name.size())));
2335
- rb_hash_aset(
2336
- index, rb_id2sym(rb_intern("datastore_id")), rb_str_new(idx.datastore_id.data(), static_cast<long>(idx.datastore_id.size())));
2337
- rb_hash_aset(
2338
- index, rb_id2sym(rb_intern("keyspace_id")), rb_str_new(idx.keyspace_id.data(), static_cast<long>(idx.keyspace_id.size())));
2339
- rb_hash_aset(
2340
- index, rb_id2sym(rb_intern("namespace_id")), rb_str_new(idx.namespace_id.data(), static_cast<long>(idx.namespace_id.size())));
2341
- rb_hash_aset(index, rb_id2sym(rb_intern("type")), rb_str_new(idx.type.data(), static_cast<long>(idx.type.size())));
2342
- rb_hash_aset(index, rb_id2sym(rb_intern("is_primary")), idx.is_primary ? Qtrue : Qfalse);
2343
- VALUE index_key = rb_ary_new_capa(static_cast<long>(idx.index_key.size()));
2344
- for (const auto& key : idx.index_key) {
2345
- rb_ary_push(index_key, rb_str_new(key.data(), static_cast<long>(key.size())));
2346
- }
2347
- rb_hash_aset(index, rb_id2sym(rb_intern("index_key")), index_key);
2348
- if (idx.condition) {
2625
+ VALUE res = rb_hash_new();
2626
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2627
+ VALUE indexes = rb_ary_new_capa(static_cast<long>(resp.indexes.size()));
2628
+ for (const auto& idx : resp.indexes) {
2629
+ VALUE index = rb_hash_new();
2630
+ rb_hash_aset(index, rb_id2sym(rb_intern("id")), rb_str_new(idx.id.data(), static_cast<long>(idx.id.size())));
2631
+ rb_hash_aset(index, rb_id2sym(rb_intern("state")), rb_str_new(idx.state.data(), static_cast<long>(idx.state.size())));
2632
+ rb_hash_aset(index, rb_id2sym(rb_intern("name")), rb_str_new(idx.name.data(), static_cast<long>(idx.name.size())));
2633
+ rb_hash_aset(
2634
+ index, rb_id2sym(rb_intern("datastore_id")), rb_str_new(idx.datastore_id.data(), static_cast<long>(idx.datastore_id.size())));
2349
2635
  rb_hash_aset(
2350
- index, rb_id2sym(rb_intern("condition")), rb_str_new(idx.condition->data(), static_cast<long>(idx.condition->size())));
2636
+ index, rb_id2sym(rb_intern("keyspace_id")), rb_str_new(idx.keyspace_id.data(), static_cast<long>(idx.keyspace_id.size())));
2637
+ rb_hash_aset(
2638
+ index, rb_id2sym(rb_intern("namespace_id")), rb_str_new(idx.namespace_id.data(), static_cast<long>(idx.namespace_id.size())));
2639
+ rb_hash_aset(index, rb_id2sym(rb_intern("type")), rb_str_new(idx.type.data(), static_cast<long>(idx.type.size())));
2640
+ rb_hash_aset(index, rb_id2sym(rb_intern("is_primary")), idx.is_primary ? Qtrue : Qfalse);
2641
+ VALUE index_key = rb_ary_new_capa(static_cast<long>(idx.index_key.size()));
2642
+ for (const auto& key : idx.index_key) {
2643
+ rb_ary_push(index_key, rb_str_new(key.data(), static_cast<long>(key.size())));
2644
+ }
2645
+ rb_hash_aset(index, rb_id2sym(rb_intern("index_key")), index_key);
2646
+ if (idx.condition) {
2647
+ rb_hash_aset(
2648
+ index, rb_id2sym(rb_intern("condition")), rb_str_new(idx.condition->data(), static_cast<long>(idx.condition->size())));
2649
+ }
2650
+ rb_ary_push(indexes, index);
2351
2651
  }
2352
- rb_ary_push(indexes, index);
2353
- }
2354
2652
 
2355
- rb_hash_aset(res, rb_id2sym(rb_intern("indexes")), indexes);
2653
+ rb_hash_aset(res, rb_id2sym(rb_intern("indexes")), indexes);
2356
2654
 
2357
- return res;
2655
+ return res;
2656
+ } while (false);
2657
+ rb_exc_raise(exc);
2658
+ return Qnil;
2358
2659
  }
2359
2660
 
2360
2661
  static VALUE
2361
- cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, VALUE fields, VALUE options)
2662
+ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, VALUE fields, VALUE options, VALUE timeout)
2362
2663
  {
2363
2664
  cb_backend_data* backend = nullptr;
2364
2665
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2371,75 +2672,83 @@ cb_Backend_query_index_create(VALUE self, VALUE bucket_name, VALUE index_name, V
2371
2672
  Check_Type(index_name, T_STRING);
2372
2673
  Check_Type(fields, T_ARRAY);
2373
2674
 
2374
- couchbase::operations::query_index_create_request req{};
2375
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2376
- req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2377
- auto fields_num = static_cast<size_t>(RARRAY_LEN(fields));
2378
- req.fields.reserve(fields_num);
2379
- for (size_t i = 0; i < fields_num; ++i) {
2380
- VALUE entry = rb_ary_entry(fields, static_cast<long>(i));
2381
- Check_Type(entry, T_STRING);
2382
- req.fields.emplace_back(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry)));
2383
- }
2384
- if (!NIL_P(options)) {
2385
- Check_Type(options, T_HASH);
2386
- VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
2387
- if (ignore_if_exists == Qtrue) {
2388
- req.ignore_if_exists = true;
2389
- } else if (ignore_if_exists == Qfalse) {
2390
- req.ignore_if_exists = false;
2391
- } /* else use backend default */
2392
- VALUE deferred = rb_hash_aref(options, rb_id2sym(rb_intern("deferred")));
2393
- if (deferred == Qtrue) {
2394
- req.deferred = true;
2395
- } else if (deferred == Qfalse) {
2396
- req.deferred = false;
2397
- } /* else use backend default */
2398
- VALUE num_replicas = rb_hash_aref(options, rb_id2sym(rb_intern("num_replicas")));
2399
- if (!NIL_P(num_replicas)) {
2400
- req.num_replicas = NUM2UINT(num_replicas);
2401
- } /* else use backend default */
2402
- VALUE condition = rb_hash_aref(options, rb_id2sym(rb_intern("condition")));
2403
- if (!NIL_P(condition)) {
2404
- req.condition.emplace(std::string(RSTRING_PTR(condition), static_cast<std::size_t>(RSTRING_LEN(condition))));
2405
- } /* else use backend default */
2406
- }
2407
-
2408
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
2409
- auto f = barrier->get_future();
2410
- backend->cluster->execute_http(
2411
- req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
2412
- auto resp = f.get();
2413
- if (resp.ec) {
2414
- if (!resp.errors.empty()) {
2415
- const auto& first_error = resp.errors.front();
2416
- cb_raise_error_code(resp.ec,
2417
- fmt::format(R"(unable to create index "{}" on the bucket "{}" ({}: {}))",
2418
- req.index_name,
2419
- req.bucket_name,
2420
- first_error.code,
2421
- first_error.message));
2422
- } else {
2423
- cb_raise_error_code(resp.ec, fmt::format(R"(unable to create index "{}" on the bucket "{}")", req.index_name, req.bucket_name));
2675
+ VALUE exc = Qnil;
2676
+ do {
2677
+ couchbase::operations::query_index_create_request req{};
2678
+ cb__extract_timeout(req, timeout);
2679
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2680
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2681
+ auto fields_num = static_cast<size_t>(RARRAY_LEN(fields));
2682
+ req.fields.reserve(fields_num);
2683
+ for (size_t i = 0; i < fields_num; ++i) {
2684
+ VALUE entry = rb_ary_entry(fields, static_cast<long>(i));
2685
+ Check_Type(entry, T_STRING);
2686
+ req.fields.emplace_back(RSTRING_PTR(entry), static_cast<std::size_t>(RSTRING_LEN(entry)));
2424
2687
  }
2425
- }
2426
- VALUE res = rb_hash_new();
2427
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2428
- if (!resp.errors.empty()) {
2429
- VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2430
- for (const auto& err : resp.errors) {
2431
- VALUE error = rb_hash_new();
2432
- rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2433
- rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2434
- rb_ary_push(errors, error);
2688
+ if (!NIL_P(options)) {
2689
+ Check_Type(options, T_HASH);
2690
+ VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
2691
+ if (ignore_if_exists == Qtrue) {
2692
+ req.ignore_if_exists = true;
2693
+ } else if (ignore_if_exists == Qfalse) {
2694
+ req.ignore_if_exists = false;
2695
+ } /* else use backend default */
2696
+ VALUE deferred = rb_hash_aref(options, rb_id2sym(rb_intern("deferred")));
2697
+ if (deferred == Qtrue) {
2698
+ req.deferred = true;
2699
+ } else if (deferred == Qfalse) {
2700
+ req.deferred = false;
2701
+ } /* else use backend default */
2702
+ VALUE num_replicas = rb_hash_aref(options, rb_id2sym(rb_intern("num_replicas")));
2703
+ if (!NIL_P(num_replicas)) {
2704
+ req.num_replicas = NUM2UINT(num_replicas);
2705
+ } /* else use backend default */
2706
+ VALUE condition = rb_hash_aref(options, rb_id2sym(rb_intern("condition")));
2707
+ if (!NIL_P(condition)) {
2708
+ req.condition.emplace(std::string(RSTRING_PTR(condition), static_cast<std::size_t>(RSTRING_LEN(condition))));
2709
+ } /* else use backend default */
2435
2710
  }
2436
- rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2437
- }
2438
- return res;
2711
+
2712
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
2713
+ auto f = barrier->get_future();
2714
+ backend->cluster->execute_http(
2715
+ req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
2716
+ auto resp = f.get();
2717
+ if (resp.ec) {
2718
+ if (!resp.errors.empty()) {
2719
+ const auto& first_error = resp.errors.front();
2720
+ exc = cb__map_error_code(resp.ec,
2721
+ fmt::format(R"(unable to create index "{}" on the bucket "{}" ({}: {}))",
2722
+ req.index_name,
2723
+ req.bucket_name,
2724
+ first_error.code,
2725
+ first_error.message));
2726
+ } else {
2727
+ exc = cb__map_error_code(resp.ec,
2728
+ fmt::format(R"(unable to create index "{}" on the bucket "{}")", req.index_name, req.bucket_name));
2729
+ }
2730
+ break;
2731
+ }
2732
+ VALUE res = rb_hash_new();
2733
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2734
+ if (!resp.errors.empty()) {
2735
+ VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2736
+ for (const auto& err : resp.errors) {
2737
+ VALUE error = rb_hash_new();
2738
+ rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2739
+ rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2740
+ rb_ary_push(errors, error);
2741
+ }
2742
+ rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2743
+ }
2744
+ return res;
2745
+ } while (false);
2746
+ rb_exc_raise(exc);
2747
+ return Qnil;
2439
2748
  }
2440
2749
 
2441
2750
  static VALUE
2442
- cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VALUE options)
2751
+ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VALUE options, VALUE timeout)
2443
2752
  {
2444
2753
  cb_backend_data* backend = nullptr;
2445
2754
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2451,54 +2760,62 @@ cb_Backend_query_index_drop(VALUE self, VALUE bucket_name, VALUE index_name, VAL
2451
2760
  Check_Type(bucket_name, T_STRING);
2452
2761
  Check_Type(index_name, T_STRING);
2453
2762
 
2454
- couchbase::operations::query_index_drop_request req{};
2455
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2456
- req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2457
- if (!NIL_P(options)) {
2458
- Check_Type(options, T_HASH);
2459
- VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
2460
- if (ignore_if_does_not_exist == Qtrue) {
2461
- req.ignore_if_does_not_exist = true;
2462
- } else if (ignore_if_does_not_exist == Qfalse) {
2463
- req.ignore_if_does_not_exist = false;
2464
- } /* else use backend default */
2465
- }
2466
-
2467
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
2468
- auto f = barrier->get_future();
2469
- backend->cluster->execute_http(req,
2470
- [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
2471
- auto resp = f.get();
2472
- if (resp.ec) {
2473
- if (!resp.errors.empty()) {
2474
- const auto& first_error = resp.errors.front();
2475
- cb_raise_error_code(resp.ec,
2476
- fmt::format(R"(unable to drop index "{}" on the bucket "{}" ({}: {}))",
2477
- req.index_name,
2478
- req.bucket_name,
2479
- first_error.code,
2480
- first_error.message));
2481
- } else {
2482
- cb_raise_error_code(resp.ec, fmt::format(R"(unable to drop index "{}" on the bucket "{}")", req.index_name, req.bucket_name));
2763
+ VALUE exc = Qnil;
2764
+ do {
2765
+ couchbase::operations::query_index_drop_request req{};
2766
+ cb__extract_timeout(req, timeout);
2767
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2768
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2769
+ if (!NIL_P(options)) {
2770
+ Check_Type(options, T_HASH);
2771
+ VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
2772
+ if (ignore_if_does_not_exist == Qtrue) {
2773
+ req.ignore_if_does_not_exist = true;
2774
+ } else if (ignore_if_does_not_exist == Qfalse) {
2775
+ req.ignore_if_does_not_exist = false;
2776
+ } /* else use backend default */
2483
2777
  }
2484
- }
2485
- VALUE res = rb_hash_new();
2486
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2487
- if (!resp.errors.empty()) {
2488
- VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2489
- for (const auto& err : resp.errors) {
2490
- VALUE error = rb_hash_new();
2491
- rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2492
- rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2493
- rb_ary_push(errors, error);
2778
+
2779
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
2780
+ auto f = barrier->get_future();
2781
+ backend->cluster->execute_http(
2782
+ req, [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
2783
+ auto resp = f.get();
2784
+ if (resp.ec) {
2785
+ if (!resp.errors.empty()) {
2786
+ const auto& first_error = resp.errors.front();
2787
+ exc = cb__map_error_code(resp.ec,
2788
+ fmt::format(R"(unable to drop index "{}" on the bucket "{}" ({}: {}))",
2789
+ req.index_name,
2790
+ req.bucket_name,
2791
+ first_error.code,
2792
+ first_error.message));
2793
+ } else {
2794
+ exc = cb__map_error_code(resp.ec,
2795
+ fmt::format(R"(unable to drop index "{}" on the bucket "{}")", req.index_name, req.bucket_name));
2796
+ }
2797
+ break;
2494
2798
  }
2495
- rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2496
- }
2497
- return res;
2799
+ VALUE res = rb_hash_new();
2800
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2801
+ if (!resp.errors.empty()) {
2802
+ VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2803
+ for (const auto& err : resp.errors) {
2804
+ VALUE error = rb_hash_new();
2805
+ rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2806
+ rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2807
+ rb_ary_push(errors, error);
2808
+ }
2809
+ rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2810
+ }
2811
+ return res;
2812
+ } while (false);
2813
+ rb_exc_raise(exc);
2814
+ return Qnil;
2498
2815
  }
2499
2816
 
2500
2817
  static VALUE
2501
- cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE options)
2818
+ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE options, VALUE timeout)
2502
2819
  {
2503
2820
  cb_backend_data* backend = nullptr;
2504
2821
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2512,67 +2829,75 @@ cb_Backend_query_index_create_primary(VALUE self, VALUE bucket_name, VALUE optio
2512
2829
  Check_Type(options, T_HASH);
2513
2830
  }
2514
2831
 
2515
- couchbase::operations::query_index_create_request req{};
2516
- req.is_primary = true;
2517
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2518
- if (!NIL_P(options)) {
2519
- Check_Type(options, T_HASH);
2520
- VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
2521
- if (ignore_if_exists == Qtrue) {
2522
- req.ignore_if_exists = true;
2523
- } else if (ignore_if_exists == Qfalse) {
2524
- req.ignore_if_exists = false;
2525
- } /* else use backend default */
2526
- VALUE deferred = rb_hash_aref(options, rb_id2sym(rb_intern("deferred")));
2527
- if (deferred == Qtrue) {
2528
- req.deferred = true;
2529
- } else if (deferred == Qfalse) {
2530
- req.deferred = false;
2531
- } /* else use backend default */
2532
- VALUE num_replicas = rb_hash_aref(options, rb_id2sym(rb_intern("num_replicas")));
2533
- if (!NIL_P(num_replicas)) {
2534
- req.num_replicas = NUM2UINT(num_replicas);
2535
- } /* else use backend default */
2536
- VALUE index_name = rb_hash_aref(options, rb_id2sym(rb_intern("index_name")));
2537
- if (!NIL_P(index_name)) {
2538
- req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2539
- } /* else use backend default */
2540
- }
2541
-
2542
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
2543
- auto f = barrier->get_future();
2544
- backend->cluster->execute_http(
2545
- req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
2546
- auto resp = f.get();
2547
- if (resp.ec) {
2548
- if (!resp.errors.empty()) {
2549
- const auto& first_error = resp.errors.front();
2550
- cb_raise_error_code(
2551
- resp.ec,
2552
- fmt::format(
2553
- R"(unable to create primary index on the bucket "{}" ({}: {}))", req.bucket_name, first_error.code, first_error.message));
2554
- } else {
2555
- cb_raise_error_code(resp.ec,
2556
- fmt::format(R"(unable to create primary index on the bucket "{}")", req.index_name, req.bucket_name));
2832
+ VALUE exc = Qnil;
2833
+ do {
2834
+ couchbase::operations::query_index_create_request req{};
2835
+ cb__extract_timeout(req, timeout);
2836
+ req.is_primary = true;
2837
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2838
+ if (!NIL_P(options)) {
2839
+ Check_Type(options, T_HASH);
2840
+ VALUE ignore_if_exists = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_exists")));
2841
+ if (ignore_if_exists == Qtrue) {
2842
+ req.ignore_if_exists = true;
2843
+ } else if (ignore_if_exists == Qfalse) {
2844
+ req.ignore_if_exists = false;
2845
+ } /* else use backend default */
2846
+ VALUE deferred = rb_hash_aref(options, rb_id2sym(rb_intern("deferred")));
2847
+ if (deferred == Qtrue) {
2848
+ req.deferred = true;
2849
+ } else if (deferred == Qfalse) {
2850
+ req.deferred = false;
2851
+ } /* else use backend default */
2852
+ VALUE num_replicas = rb_hash_aref(options, rb_id2sym(rb_intern("num_replicas")));
2853
+ if (!NIL_P(num_replicas)) {
2854
+ req.num_replicas = NUM2UINT(num_replicas);
2855
+ } /* else use backend default */
2856
+ VALUE index_name = rb_hash_aref(options, rb_id2sym(rb_intern("index_name")));
2857
+ if (!NIL_P(index_name)) {
2858
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2859
+ } /* else use backend default */
2557
2860
  }
2558
- }
2559
- VALUE res = rb_hash_new();
2560
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2561
- if (!resp.errors.empty()) {
2562
- VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2563
- for (const auto& err : resp.errors) {
2564
- VALUE error = rb_hash_new();
2565
- rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2566
- rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2567
- rb_ary_push(errors, error);
2861
+
2862
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_create_response>>();
2863
+ auto f = barrier->get_future();
2864
+ backend->cluster->execute_http(
2865
+ req, [barrier](couchbase::operations::query_index_create_response resp) mutable { barrier->set_value(resp); });
2866
+ auto resp = f.get();
2867
+ if (resp.ec) {
2868
+ if (!resp.errors.empty()) {
2869
+ const auto& first_error = resp.errors.front();
2870
+ exc = cb__map_error_code(resp.ec,
2871
+ fmt::format(R"(unable to create primary index on the bucket "{}" ({}: {}))",
2872
+ req.bucket_name,
2873
+ first_error.code,
2874
+ first_error.message));
2875
+ } else {
2876
+ exc = cb__map_error_code(
2877
+ resp.ec, fmt::format(R"(unable to create primary index on the bucket "{}")", req.index_name, req.bucket_name));
2878
+ }
2879
+ break;
2568
2880
  }
2569
- rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2570
- }
2571
- return res;
2881
+ VALUE res = rb_hash_new();
2882
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2883
+ if (!resp.errors.empty()) {
2884
+ VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2885
+ for (const auto& err : resp.errors) {
2886
+ VALUE error = rb_hash_new();
2887
+ rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2888
+ rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2889
+ rb_ary_push(errors, error);
2890
+ }
2891
+ rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2892
+ }
2893
+ return res;
2894
+ } while (false);
2895
+ rb_exc_raise(exc);
2896
+ return Qnil;
2572
2897
  }
2573
2898
 
2574
2899
  static VALUE
2575
- cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options)
2900
+ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options, VALUE timeout)
2576
2901
  {
2577
2902
  cb_backend_data* backend = nullptr;
2578
2903
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2583,58 +2908,65 @@ cb_Backend_query_index_drop_primary(VALUE self, VALUE bucket_name, VALUE options
2583
2908
 
2584
2909
  Check_Type(bucket_name, T_STRING);
2585
2910
 
2586
- couchbase::operations::query_index_drop_request req{};
2587
- req.is_primary = true;
2588
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2589
- if (!NIL_P(options)) {
2590
- Check_Type(options, T_HASH);
2591
- VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
2592
- if (ignore_if_does_not_exist == Qtrue) {
2593
- req.ignore_if_does_not_exist = true;
2594
- } else if (ignore_if_does_not_exist == Qfalse) {
2595
- req.ignore_if_does_not_exist = false;
2596
- } /* else use backend default */
2597
- VALUE index_name = rb_hash_aref(options, rb_id2sym(rb_intern("index_name")));
2598
- if (!NIL_P(index_name)) {
2599
- Check_Type(options, T_STRING);
2600
- req.is_primary = false;
2601
- req.bucket_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2602
- }
2603
- }
2604
-
2605
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
2606
- auto f = barrier->get_future();
2607
- backend->cluster->execute_http(req,
2608
- [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
2609
- auto resp = f.get();
2610
- if (resp.ec) {
2611
- if (!resp.errors.empty()) {
2612
- const auto& first_error = resp.errors.front();
2613
- cb_raise_error_code(
2614
- resp.ec,
2615
- fmt::format(
2616
- R"(unable to drop primary index on the bucket "{}" ({}: {}))", req.bucket_name, first_error.code, first_error.message));
2617
- } else {
2618
- cb_raise_error_code(resp.ec, fmt::format(R"(unable to drop primary index on the bucket "{}")", req.bucket_name));
2911
+ VALUE exc = Qnil;
2912
+ do {
2913
+ couchbase::operations::query_index_drop_request req{};
2914
+ cb__extract_timeout(req, timeout);
2915
+ req.is_primary = true;
2916
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2917
+ if (!NIL_P(options)) {
2918
+ Check_Type(options, T_HASH);
2919
+ VALUE ignore_if_does_not_exist = rb_hash_aref(options, rb_id2sym(rb_intern("ignore_if_does_not_exist")));
2920
+ if (ignore_if_does_not_exist == Qtrue) {
2921
+ req.ignore_if_does_not_exist = true;
2922
+ } else if (ignore_if_does_not_exist == Qfalse) {
2923
+ req.ignore_if_does_not_exist = false;
2924
+ } /* else use backend default */
2925
+ VALUE index_name = rb_hash_aref(options, rb_id2sym(rb_intern("index_name")));
2926
+ if (!NIL_P(index_name)) {
2927
+ Check_Type(options, T_STRING);
2928
+ req.is_primary = false;
2929
+ req.bucket_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
2930
+ }
2619
2931
  }
2620
- }
2621
- VALUE res = rb_hash_new();
2622
- rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2623
- if (!resp.errors.empty()) {
2624
- VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2625
- for (const auto& err : resp.errors) {
2626
- VALUE error = rb_hash_new();
2627
- rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2628
- rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2629
- rb_ary_push(errors, error);
2932
+
2933
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_drop_response>>();
2934
+ auto f = barrier->get_future();
2935
+ backend->cluster->execute_http(
2936
+ req, [barrier](couchbase::operations::query_index_drop_response resp) mutable { barrier->set_value(resp); });
2937
+ auto resp = f.get();
2938
+ if (resp.ec) {
2939
+ if (!resp.errors.empty()) {
2940
+ const auto& first_error = resp.errors.front();
2941
+ exc = cb__map_error_code(
2942
+ resp.ec,
2943
+ fmt::format(
2944
+ R"(unable to drop primary index on the bucket "{}" ({}: {}))", req.bucket_name, first_error.code, first_error.message));
2945
+ } else {
2946
+ exc = cb__map_error_code(resp.ec, fmt::format(R"(unable to drop primary index on the bucket "{}")", req.bucket_name));
2947
+ }
2948
+ break;
2630
2949
  }
2631
- rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2632
- }
2633
- return res;
2950
+ VALUE res = rb_hash_new();
2951
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
2952
+ if (!resp.errors.empty()) {
2953
+ VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
2954
+ for (const auto& err : resp.errors) {
2955
+ VALUE error = rb_hash_new();
2956
+ rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
2957
+ rb_hash_aset(error, rb_id2sym(rb_intern("message")), rb_str_new(err.message.data(), static_cast<long>(err.message.size())));
2958
+ rb_ary_push(errors, error);
2959
+ }
2960
+ rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
2961
+ }
2962
+ return res;
2963
+ } while (false);
2964
+ rb_exc_raise(exc);
2965
+ return Qnil;
2634
2966
  }
2635
2967
 
2636
2968
  static VALUE
2637
- cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE options)
2969
+ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE timeout)
2638
2970
  {
2639
2971
  cb_backend_data* backend = nullptr;
2640
2972
  TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
@@ -2644,31 +2976,35 @@ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE optio
2644
2976
  }
2645
2977
 
2646
2978
  Check_Type(bucket_name, T_STRING);
2647
- if (!NIL_P(options)) {
2648
- Check_Type(options, T_HASH);
2649
- }
2650
2979
 
2651
- couchbase::operations::query_index_build_deferred_request req{};
2652
- req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2653
- auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_build_deferred_response>>();
2654
- auto f = barrier->get_future();
2655
- backend->cluster->execute_http(
2656
- req, [barrier](couchbase::operations::query_index_build_deferred_response resp) mutable { barrier->set_value(resp); });
2657
- auto resp = f.get();
2658
- if (resp.ec) {
2659
- if (!resp.errors.empty()) {
2660
- const auto& first_error = resp.errors.front();
2661
- cb_raise_error_code(
2662
- resp.ec,
2663
- fmt::format(
2664
- R"(unable to drop primary index on the bucket "{}" ({}: {}))", req.bucket_name, first_error.code, first_error.message));
2980
+ VALUE exc = Qnil;
2981
+ do {
2982
+ couchbase::operations::query_index_build_deferred_request req{};
2983
+ cb__extract_timeout(req, timeout);
2984
+ req.bucket_name.assign(RSTRING_PTR(bucket_name), static_cast<size_t>(RSTRING_LEN(bucket_name)));
2985
+ auto barrier = std::make_shared<std::promise<couchbase::operations::query_index_build_deferred_response>>();
2986
+ auto f = barrier->get_future();
2987
+ backend->cluster->execute_http(
2988
+ req, [barrier](couchbase::operations::query_index_build_deferred_response resp) mutable { barrier->set_value(resp); });
2989
+ auto resp = f.get();
2990
+ if (resp.ec) {
2991
+ if (!resp.errors.empty()) {
2992
+ const auto& first_error = resp.errors.front();
2993
+ exc = cb__map_error_code(
2994
+ resp.ec,
2995
+ fmt::format(
2996
+ R"(unable to drop primary index on the bucket "{}" ({}: {}))", req.bucket_name, first_error.code, first_error.message));
2665
2997
 
2666
- } else {
2667
- cb_raise_error_code(resp.ec,
2668
- fmt::format("unable to trigger build for deferred indexes for the bucket \"{}\"", req.bucket_name));
2998
+ } else {
2999
+ exc = cb__map_error_code(
3000
+ resp.ec, fmt::format("unable to trigger build for deferred indexes for the bucket \"{}\"", req.bucket_name));
3001
+ }
3002
+ break;
2669
3003
  }
2670
- }
2671
- return Qtrue;
3004
+ return Qtrue;
3005
+ } while (false);
3006
+ rb_exc_raise(exc);
3007
+ return Qnil;
2672
3008
  }
2673
3009
 
2674
3010
  static VALUE
@@ -2692,52 +3028,926 @@ cb_Backend_query_index_watch(VALUE self, VALUE bucket_name, VALUE index_names, V
2692
3028
  }
2693
3029
 
2694
3030
  static void
2695
- init_backend(VALUE mCouchbase)
3031
+ cb__extract_search_index(VALUE index, const couchbase::operations::search_index& idx)
2696
3032
  {
2697
- VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cBasicObject);
2698
- rb_define_alloc_func(cBackend, cb_Backend_allocate);
2699
- rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open), 3);
2700
- rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
2701
- rb_define_method(cBackend, "open_bucket", VALUE_FUNC(cb_Backend_open_bucket), 1);
3033
+ rb_hash_aset(index, rb_id2sym(rb_intern("uuid")), rb_str_new(idx.uuid.data(), static_cast<long>(idx.uuid.size())));
3034
+ rb_hash_aset(index, rb_id2sym(rb_intern("name")), rb_str_new(idx.name.data(), static_cast<long>(idx.name.size())));
3035
+ rb_hash_aset(index, rb_id2sym(rb_intern("type")), rb_str_new(idx.type.data(), static_cast<long>(idx.type.size())));
3036
+ if (!idx.params_json.empty()) {
3037
+ rb_hash_aset(index, rb_id2sym(rb_intern("params")), rb_str_new(idx.params_json.data(), static_cast<long>(idx.params_json.size())));
3038
+ }
2702
3039
 
2703
- rb_define_method(cBackend, "document_get", VALUE_FUNC(cb_Backend_document_get), 3);
2704
- rb_define_method(cBackend, "document_get_and_lock", VALUE_FUNC(cb_Backend_document_get_and_lock), 4);
2705
- rb_define_method(cBackend, "document_get_and_touch", VALUE_FUNC(cb_Backend_document_get_and_touch), 4);
2706
- rb_define_method(cBackend, "document_insert", VALUE_FUNC(cb_Backend_document_insert), 6);
2707
- rb_define_method(cBackend, "document_replace", VALUE_FUNC(cb_Backend_document_replace), 6);
2708
- rb_define_method(cBackend, "document_upsert", VALUE_FUNC(cb_Backend_document_upsert), 6);
2709
- rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 4);
2710
- rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 5);
2711
- rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 6);
2712
- rb_define_method(cBackend, "document_query", VALUE_FUNC(cb_Backend_document_query), 2);
2713
- rb_define_method(cBackend, "document_touch", VALUE_FUNC(cb_Backend_document_touch), 4);
2714
- rb_define_method(cBackend, "document_exists", VALUE_FUNC(cb_Backend_document_exists), 3);
2715
- rb_define_method(cBackend, "document_unlock", VALUE_FUNC(cb_Backend_document_unlock), 4);
2716
- rb_define_method(cBackend, "document_increment", VALUE_FUNC(cb_Backend_document_increment), 4);
2717
- rb_define_method(cBackend, "document_decrement", VALUE_FUNC(cb_Backend_document_decrement), 4);
2718
-
2719
- rb_define_method(cBackend, "bucket_create", VALUE_FUNC(cb_Backend_bucket_create), 1);
2720
- rb_define_method(cBackend, "bucket_update", VALUE_FUNC(cb_Backend_bucket_update), 1);
2721
- rb_define_method(cBackend, "bucket_drop", VALUE_FUNC(cb_Backend_bucket_drop), 1);
2722
- rb_define_method(cBackend, "bucket_flush", VALUE_FUNC(cb_Backend_bucket_flush), 1);
2723
- rb_define_method(cBackend, "bucket_get_all", VALUE_FUNC(cb_Backend_bucket_get_all), 0);
2724
- rb_define_method(cBackend, "bucket_get", VALUE_FUNC(cb_Backend_bucket_get), 1);
3040
+ if (!idx.source_uuid.empty()) {
3041
+ rb_hash_aset(
3042
+ index, rb_id2sym(rb_intern("source_uuid")), rb_str_new(idx.source_uuid.data(), static_cast<long>(idx.source_uuid.size())));
3043
+ }
3044
+ if (!idx.source_name.empty()) {
3045
+ rb_hash_aset(
3046
+ index, rb_id2sym(rb_intern("source_name")), rb_str_new(idx.source_name.data(), static_cast<long>(idx.source_name.size())));
3047
+ }
3048
+ rb_hash_aset(index, rb_id2sym(rb_intern("source_type")), rb_str_new(idx.source_type.data(), static_cast<long>(idx.source_type.size())));
3049
+ if (!idx.source_params_json.empty()) {
3050
+ rb_hash_aset(index,
3051
+ rb_id2sym(rb_intern("source_params")),
3052
+ rb_str_new(idx.source_params_json.data(), static_cast<long>(idx.source_params_json.size())));
3053
+ }
3054
+ if (!idx.plan_params_json.empty()) {
3055
+ rb_hash_aset(index,
3056
+ rb_id2sym(rb_intern("plan_params")),
3057
+ rb_str_new(idx.plan_params_json.data(), static_cast<long>(idx.plan_params_json.size())));
3058
+ }
3059
+ }
2725
3060
 
2726
- rb_define_method(cBackend, "cluster_enable_developer_preview!", VALUE_FUNC(cb_Backend_cluster_enable_developer_preview), 0);
3061
+ static VALUE
3062
+ cb_Backend_search_index_get_all(VALUE self, VALUE timeout)
3063
+ {
3064
+ cb_backend_data* backend = nullptr;
3065
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
2727
3066
 
2728
- rb_define_method(cBackend, "scope_get_all", VALUE_FUNC(cb_Backend_scope_get_all), 1);
2729
- rb_define_method(cBackend, "scope_create", VALUE_FUNC(cb_Backend_scope_create), 2);
2730
- rb_define_method(cBackend, "scope_drop", VALUE_FUNC(cb_Backend_scope_drop), 2);
2731
- rb_define_method(cBackend, "collection_create", VALUE_FUNC(cb_Backend_collection_create), 4);
2732
- rb_define_method(cBackend, "collection_drop", VALUE_FUNC(cb_Backend_collection_drop), 3);
2733
-
2734
- rb_define_method(cBackend, "query_index_get_all", VALUE_FUNC(cb_Backend_query_index_get_all), 1);
2735
- rb_define_method(cBackend, "query_index_create", VALUE_FUNC(cb_Backend_query_index_create), 4);
2736
- rb_define_method(cBackend, "query_index_create_primary", VALUE_FUNC(cb_Backend_query_index_create_primary), 2);
2737
- rb_define_method(cBackend, "query_index_drop", VALUE_FUNC(cb_Backend_query_index_drop), 3);
2738
- rb_define_method(cBackend, "query_index_drop_primary", VALUE_FUNC(cb_Backend_query_index_drop_primary), 2);
2739
- rb_define_method(cBackend, "query_index_build_deferred", VALUE_FUNC(cb_Backend_query_index_build_deferred), 2);
2740
- rb_define_method(cBackend, "query_index_watch", VALUE_FUNC(cb_Backend_query_index_watch), 4);
3067
+ if (!backend->cluster) {
3068
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3069
+ }
3070
+
3071
+ VALUE exc = Qnil;
3072
+ do {
3073
+ couchbase::operations::search_index_get_all_request req{};
3074
+ cb__extract_timeout(req, timeout);
3075
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_all_response>>();
3076
+ auto f = barrier->get_future();
3077
+ backend->cluster->execute_http(
3078
+ req, [barrier](couchbase::operations::search_index_get_all_response resp) mutable { barrier->set_value(resp); });
3079
+ auto resp = f.get();
3080
+ if (resp.ec) {
3081
+ exc = cb__map_error_code(resp.ec, "unable to get list of the search indexes");
3082
+ break;
3083
+ }
3084
+ VALUE res = rb_hash_new();
3085
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3086
+ rb_hash_aset(
3087
+ res, rb_id2sym(rb_intern("impl_version")), rb_str_new(resp.impl_version.data(), static_cast<long>(resp.impl_version.size())));
3088
+ VALUE indexes = rb_ary_new_capa(static_cast<long>(resp.indexes.size()));
3089
+ for (const auto& idx : resp.indexes) {
3090
+ VALUE index = rb_hash_new();
3091
+ cb__extract_search_index(index, idx);
3092
+ rb_ary_push(indexes, index);
3093
+ }
3094
+ rb_hash_aset(res, rb_id2sym(rb_intern("indexes")), indexes);
3095
+ return res;
3096
+ } while (false);
3097
+ rb_exc_raise(exc);
3098
+ return Qnil;
3099
+ }
3100
+
3101
+ static VALUE
3102
+ cb_Backend_search_index_get(VALUE self, VALUE index_name, VALUE timeout)
3103
+ {
3104
+ cb_backend_data* backend = nullptr;
3105
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3106
+
3107
+ if (!backend->cluster) {
3108
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3109
+ }
3110
+
3111
+ Check_Type(index_name, T_STRING);
3112
+ VALUE exc = Qnil;
3113
+ do {
3114
+ couchbase::operations::search_index_get_request req{};
3115
+ cb__extract_timeout(req, timeout);
3116
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3117
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_response>>();
3118
+ auto f = barrier->get_future();
3119
+ backend->cluster->execute_http(
3120
+ req, [barrier](couchbase::operations::search_index_get_response resp) mutable { barrier->set_value(resp); });
3121
+ auto resp = f.get();
3122
+ if (resp.ec) {
3123
+ if (resp.error.empty()) {
3124
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to get search index \"{}\"", req.index_name));
3125
+ } else {
3126
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to get search index \"{}\": {}", req.index_name, resp.error));
3127
+ }
3128
+ break;
3129
+ }
3130
+ VALUE res = rb_hash_new();
3131
+ cb__extract_search_index(res, resp.index);
3132
+ return res;
3133
+ } while (false);
3134
+ rb_exc_raise(exc);
3135
+ return Qnil;
3136
+ }
3137
+
3138
+ static VALUE
3139
+ cb_Backend_search_index_upsert(VALUE self, VALUE index_definition, VALUE timeout)
3140
+ {
3141
+ cb_backend_data* backend = nullptr;
3142
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3143
+
3144
+ if (!backend->cluster) {
3145
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3146
+ }
3147
+
3148
+ Check_Type(index_definition, T_HASH);
3149
+ VALUE exc = Qnil;
3150
+ do {
3151
+ couchbase::operations::search_index_upsert_request req{};
3152
+ cb__extract_timeout(req, timeout);
3153
+
3154
+ VALUE index_name = rb_hash_aref(index_definition, rb_id2sym(rb_intern("name")));
3155
+ Check_Type(index_name, T_STRING);
3156
+ req.index.name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3157
+
3158
+ VALUE index_type = rb_hash_aref(index_definition, rb_id2sym(rb_intern("type")));
3159
+ Check_Type(index_type, T_STRING);
3160
+ req.index.type.assign(RSTRING_PTR(index_type), static_cast<size_t>(RSTRING_LEN(index_type)));
3161
+
3162
+ VALUE index_uuid = rb_hash_aref(index_definition, rb_id2sym(rb_intern("uuid")));
3163
+ if (!NIL_P(index_uuid)) {
3164
+ Check_Type(index_uuid, T_STRING);
3165
+ req.index.uuid.assign(RSTRING_PTR(index_uuid), static_cast<size_t>(RSTRING_LEN(index_uuid)));
3166
+ }
3167
+
3168
+ VALUE index_params = rb_hash_aref(index_definition, rb_id2sym(rb_intern("params")));
3169
+ if (!NIL_P(index_params)) {
3170
+ Check_Type(index_params, T_STRING);
3171
+ req.index.params_json.assign(std::string(RSTRING_PTR(index_params), static_cast<size_t>(RSTRING_LEN(index_params))));
3172
+ }
3173
+
3174
+ VALUE source_name = rb_hash_aref(index_definition, rb_id2sym(rb_intern("source_name")));
3175
+ if (!NIL_P(source_name)) {
3176
+ Check_Type(source_name, T_STRING);
3177
+ req.index.source_name.assign(RSTRING_PTR(source_name), static_cast<size_t>(RSTRING_LEN(source_name)));
3178
+ }
3179
+
3180
+ VALUE source_type = rb_hash_aref(index_definition, rb_id2sym(rb_intern("source_type")));
3181
+ Check_Type(source_type, T_STRING);
3182
+ req.index.source_type.assign(RSTRING_PTR(source_type), static_cast<size_t>(RSTRING_LEN(source_type)));
3183
+
3184
+ VALUE source_uuid = rb_hash_aref(index_definition, rb_id2sym(rb_intern("source_uuid")));
3185
+ if (!NIL_P(source_uuid)) {
3186
+ Check_Type(source_uuid, T_STRING);
3187
+ req.index.source_uuid.assign(RSTRING_PTR(source_uuid), static_cast<size_t>(RSTRING_LEN(source_uuid)));
3188
+ }
3189
+
3190
+ VALUE source_params = rb_hash_aref(index_definition, rb_id2sym(rb_intern("source_params")));
3191
+ if (!NIL_P(source_params)) {
3192
+ Check_Type(source_params, T_STRING);
3193
+ req.index.source_params_json.assign(std::string(RSTRING_PTR(source_params), static_cast<size_t>(RSTRING_LEN(source_params))));
3194
+ }
3195
+
3196
+ VALUE plan_params = rb_hash_aref(index_definition, rb_id2sym(rb_intern("plan_params")));
3197
+ if (!NIL_P(plan_params)) {
3198
+ Check_Type(plan_params, T_STRING);
3199
+ req.index.plan_params_json.assign(std::string(RSTRING_PTR(plan_params), static_cast<size_t>(RSTRING_LEN(plan_params))));
3200
+ }
3201
+
3202
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_upsert_response>>();
3203
+ auto f = barrier->get_future();
3204
+ backend->cluster->execute_http(
3205
+ req, [barrier](couchbase::operations::search_index_upsert_response resp) mutable { barrier->set_value(resp); });
3206
+ auto resp = f.get();
3207
+ if (resp.ec) {
3208
+ if (resp.error.empty()) {
3209
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to upsert the search index \"{}\"", req.index.name));
3210
+ } else {
3211
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to upsert the search index \"{}\": {}", req.index.name, resp.error));
3212
+ }
3213
+ break;
3214
+ }
3215
+ VALUE res = rb_hash_new();
3216
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3217
+ return res;
3218
+ } while (false);
3219
+ rb_exc_raise(exc);
3220
+ return Qnil;
3221
+ }
3222
+
3223
+ static VALUE
3224
+ cb_Backend_search_index_drop(VALUE self, VALUE index_name, VALUE timeout)
3225
+ {
3226
+ cb_backend_data* backend = nullptr;
3227
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3228
+
3229
+ if (!backend->cluster) {
3230
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3231
+ }
3232
+
3233
+ Check_Type(index_name, T_STRING);
3234
+ VALUE exc = Qnil;
3235
+ do {
3236
+ couchbase::operations::search_index_drop_request req{};
3237
+ cb__extract_timeout(req, timeout);
3238
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3239
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_drop_response>>();
3240
+ auto f = barrier->get_future();
3241
+ backend->cluster->execute_http(
3242
+ req, [barrier](couchbase::operations::search_index_drop_response resp) mutable { barrier->set_value(resp); });
3243
+ auto resp = f.get();
3244
+ if (resp.ec) {
3245
+ if (resp.error.empty()) {
3246
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to drop the search index \"{}\"", req.index_name));
3247
+ } else {
3248
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to drop the search index \"{}\": {}", req.index_name, resp.error));
3249
+ }
3250
+ break;
3251
+ }
3252
+ VALUE res = rb_hash_new();
3253
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3254
+ return res;
3255
+ } while (false);
3256
+ rb_exc_raise(exc);
3257
+ return Qnil;
3258
+ }
3259
+
3260
+ static VALUE
3261
+ cb_Backend_search_index_get_documents_count(VALUE self, VALUE index_name, VALUE timeout)
3262
+ {
3263
+ cb_backend_data* backend = nullptr;
3264
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3265
+
3266
+ if (!backend->cluster) {
3267
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3268
+ }
3269
+
3270
+ Check_Type(index_name, T_STRING);
3271
+ VALUE exc = Qnil;
3272
+ do {
3273
+ couchbase::operations::search_index_get_documents_count_request req{};
3274
+ cb__extract_timeout(req, timeout);
3275
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3276
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_get_documents_count_response>>();
3277
+ auto f = barrier->get_future();
3278
+ backend->cluster->execute_http(
3279
+ req, [barrier](couchbase::operations::search_index_get_documents_count_response resp) mutable { barrier->set_value(resp); });
3280
+ auto resp = f.get();
3281
+ if (resp.ec) {
3282
+ if (resp.error.empty()) {
3283
+ exc = cb__map_error_code(
3284
+ resp.ec, fmt::format("unable to get number of the indexed documents for the search index \"{}\"", req.index_name));
3285
+ } else {
3286
+ exc = cb__map_error_code(
3287
+ resp.ec,
3288
+ fmt::format("unable to get number of the indexed documents for the search index \"{}\": {}", req.index_name, resp.error));
3289
+ }
3290
+ break;
3291
+ }
3292
+ VALUE res = rb_hash_new();
3293
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3294
+ rb_hash_aset(res, rb_id2sym(rb_intern("count")), ULL2NUM(resp.count));
3295
+ return res;
3296
+ } while (false);
3297
+ rb_exc_raise(exc);
3298
+ return Qnil;
3299
+ }
3300
+
3301
+ static VALUE
3302
+ cb_Backend_search_index_pause_ingest(VALUE self, VALUE index_name, VALUE timeout)
3303
+ {
3304
+ cb_backend_data* backend = nullptr;
3305
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3306
+
3307
+ if (!backend->cluster) {
3308
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3309
+ }
3310
+
3311
+ Check_Type(index_name, T_STRING);
3312
+ VALUE exc = Qnil;
3313
+ do {
3314
+ couchbase::operations::search_index_control_ingest_request req{};
3315
+ cb__extract_timeout(req, timeout);
3316
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3317
+ req.pause = true;
3318
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_ingest_response>>();
3319
+ auto f = barrier->get_future();
3320
+ backend->cluster->execute_http(
3321
+ req, [barrier](couchbase::operations::search_index_control_ingest_response resp) mutable { barrier->set_value(resp); });
3322
+ auto resp = f.get();
3323
+ if (resp.ec) {
3324
+ if (resp.error.empty()) {
3325
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to pause ingest for the search index \"{}\"", req.index_name));
3326
+ } else {
3327
+ exc = cb__map_error_code(resp.ec,
3328
+ fmt::format("unable to pause ingest for the search index \"{}\": {}", req.index_name, resp.error));
3329
+ }
3330
+ break;
3331
+ }
3332
+ VALUE res = rb_hash_new();
3333
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3334
+ return res;
3335
+ } while (false);
3336
+ rb_exc_raise(exc);
3337
+ return Qnil;
3338
+ }
3339
+
3340
+ static VALUE
3341
+ cb_Backend_search_index_resume_ingest(VALUE self, VALUE index_name, VALUE timeout)
3342
+ {
3343
+ cb_backend_data* backend = nullptr;
3344
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3345
+
3346
+ if (!backend->cluster) {
3347
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3348
+ }
3349
+
3350
+ Check_Type(index_name, T_STRING);
3351
+ VALUE exc = Qnil;
3352
+ do {
3353
+ couchbase::operations::search_index_control_ingest_request req{};
3354
+ cb__extract_timeout(req, timeout);
3355
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3356
+ req.pause = false;
3357
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_ingest_response>>();
3358
+ auto f = barrier->get_future();
3359
+ backend->cluster->execute_http(
3360
+ req, [barrier](couchbase::operations::search_index_control_ingest_response resp) mutable { barrier->set_value(resp); });
3361
+ auto resp = f.get();
3362
+ if (resp.ec) {
3363
+ if (resp.error.empty()) {
3364
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to resume ingest for the search index \"{}\"", req.index_name));
3365
+ } else {
3366
+ exc = cb__map_error_code(
3367
+ resp.ec, fmt::format("unable to resume ingest for the search index \"{}\": {}", req.index_name, resp.error));
3368
+ }
3369
+ break;
3370
+ }
3371
+ VALUE res = rb_hash_new();
3372
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3373
+ return res;
3374
+ } while (false);
3375
+ rb_exc_raise(exc);
3376
+ return Qnil;
3377
+ }
3378
+
3379
+ static VALUE
3380
+ cb_Backend_search_index_allow_querying(VALUE self, VALUE index_name, VALUE timeout)
3381
+ {
3382
+ cb_backend_data* backend = nullptr;
3383
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3384
+
3385
+ if (!backend->cluster) {
3386
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3387
+ }
3388
+
3389
+ Check_Type(index_name, T_STRING);
3390
+ VALUE exc = Qnil;
3391
+ do {
3392
+ couchbase::operations::search_index_control_query_request req{};
3393
+ cb__extract_timeout(req, timeout);
3394
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3395
+ req.allow = true;
3396
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_query_response>>();
3397
+ auto f = barrier->get_future();
3398
+ backend->cluster->execute_http(
3399
+ req, [barrier](couchbase::operations::search_index_control_query_response resp) mutable { barrier->set_value(resp); });
3400
+ auto resp = f.get();
3401
+ if (resp.ec) {
3402
+ if (resp.error.empty()) {
3403
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to allow querying for the search index \"{}\"", req.index_name));
3404
+ } else {
3405
+ exc = cb__map_error_code(
3406
+ resp.ec, fmt::format("unable to allow querying for the search index \"{}\": {}", req.index_name, resp.error));
3407
+ }
3408
+ break;
3409
+ }
3410
+ VALUE res = rb_hash_new();
3411
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3412
+ return res;
3413
+ } while (false);
3414
+ rb_exc_raise(exc);
3415
+ return Qnil;
3416
+ }
3417
+
3418
+ static VALUE
3419
+ cb_Backend_search_index_disallow_querying(VALUE self, VALUE index_name, VALUE timeout)
3420
+ {
3421
+ cb_backend_data* backend = nullptr;
3422
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3423
+
3424
+ if (!backend->cluster) {
3425
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3426
+ }
3427
+
3428
+ Check_Type(index_name, T_STRING);
3429
+ VALUE exc = Qnil;
3430
+ do {
3431
+ couchbase::operations::search_index_control_query_request req{};
3432
+ cb__extract_timeout(req, timeout);
3433
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3434
+ req.allow = false;
3435
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_query_response>>();
3436
+ auto f = barrier->get_future();
3437
+ backend->cluster->execute_http(
3438
+ req, [barrier](couchbase::operations::search_index_control_query_response resp) mutable { barrier->set_value(resp); });
3439
+ auto resp = f.get();
3440
+ if (resp.ec) {
3441
+ if (resp.error.empty()) {
3442
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to disallow querying for the search index \"{}\"", req.index_name));
3443
+ } else {
3444
+ exc = cb__map_error_code(
3445
+ resp.ec, fmt::format("unable to disallow querying for the search index \"{}\": {}", req.index_name, resp.error));
3446
+ }
3447
+ break;
3448
+ }
3449
+ VALUE res = rb_hash_new();
3450
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3451
+ return res;
3452
+ } while (false);
3453
+ rb_exc_raise(exc);
3454
+ return Qnil;
3455
+ }
3456
+
3457
+ static VALUE
3458
+ cb_Backend_search_index_freeze_plan(VALUE self, VALUE index_name, VALUE timeout)
3459
+ {
3460
+ cb_backend_data* backend = nullptr;
3461
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3462
+
3463
+ if (!backend->cluster) {
3464
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3465
+ }
3466
+
3467
+ Check_Type(index_name, T_STRING);
3468
+ VALUE exc = Qnil;
3469
+ do {
3470
+ couchbase::operations::search_index_control_plan_freeze_request req{};
3471
+ cb__extract_timeout(req, timeout);
3472
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3473
+ req.freeze = true;
3474
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_plan_freeze_response>>();
3475
+ auto f = barrier->get_future();
3476
+ backend->cluster->execute_http(
3477
+ req, [barrier](couchbase::operations::search_index_control_plan_freeze_response resp) mutable { barrier->set_value(resp); });
3478
+ auto resp = f.get();
3479
+ if (resp.ec) {
3480
+ if (resp.error.empty()) {
3481
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to freeze for the search index \"{}\"", req.index_name));
3482
+ } else {
3483
+ exc =
3484
+ cb__map_error_code(resp.ec, fmt::format("unable to freeze for the search index \"{}\": {}", req.index_name, resp.error));
3485
+ }
3486
+ break;
3487
+ }
3488
+ VALUE res = rb_hash_new();
3489
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3490
+ return res;
3491
+ } while (false);
3492
+ rb_exc_raise(exc);
3493
+ return Qnil;
3494
+ }
3495
+
3496
+ static VALUE
3497
+ cb_Backend_search_index_unfreeze_plan(VALUE self, VALUE index_name, VALUE timeout)
3498
+ {
3499
+ cb_backend_data* backend = nullptr;
3500
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3501
+
3502
+ if (!backend->cluster) {
3503
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3504
+ }
3505
+
3506
+ Check_Type(index_name, T_STRING);
3507
+ VALUE exc = Qnil;
3508
+ do {
3509
+ couchbase::operations::search_index_control_plan_freeze_request req{};
3510
+ cb__extract_timeout(req, timeout);
3511
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3512
+ req.freeze = false;
3513
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_control_plan_freeze_response>>();
3514
+ auto f = barrier->get_future();
3515
+ backend->cluster->execute_http(
3516
+ req, [barrier](couchbase::operations::search_index_control_plan_freeze_response resp) mutable { barrier->set_value(resp); });
3517
+ auto resp = f.get();
3518
+ if (resp.ec) {
3519
+ if (resp.error.empty()) {
3520
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to unfreeze plan for the search index \"{}\"", req.index_name));
3521
+ } else {
3522
+ exc = cb__map_error_code(resp.ec,
3523
+ fmt::format("unable to unfreeze for the search index \"{}\": {}", req.index_name, resp.error));
3524
+ }
3525
+ break;
3526
+ }
3527
+ VALUE res = rb_hash_new();
3528
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3529
+ return res;
3530
+ } while (false);
3531
+ rb_exc_raise(exc);
3532
+ return Qnil;
3533
+ }
3534
+
3535
+ static VALUE
3536
+ cb_Backend_search_index_analyze_document(VALUE self, VALUE index_name, VALUE encoded_document, VALUE timeout)
3537
+ {
3538
+ cb_backend_data* backend = nullptr;
3539
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3540
+
3541
+ if (!backend->cluster) {
3542
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3543
+ }
3544
+
3545
+ Check_Type(index_name, T_STRING);
3546
+ Check_Type(encoded_document, T_STRING);
3547
+ VALUE exc = Qnil;
3548
+ do {
3549
+ couchbase::operations::search_index_analyze_document_request req{};
3550
+ cb__extract_timeout(req, timeout);
3551
+
3552
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3553
+ req.encoded_document.assign(RSTRING_PTR(encoded_document), static_cast<size_t>(RSTRING_LEN(encoded_document)));
3554
+
3555
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_index_analyze_document_response>>();
3556
+ auto f = barrier->get_future();
3557
+ backend->cluster->execute_http(
3558
+ req, [barrier](couchbase::operations::search_index_analyze_document_response resp) mutable { barrier->set_value(resp); });
3559
+ auto resp = f.get();
3560
+ if (resp.ec) {
3561
+ if (resp.error.empty()) {
3562
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to analyze document using the search index \"{}\"", req.index_name));
3563
+ } else {
3564
+ exc = cb__map_error_code(
3565
+ resp.ec, fmt::format("unable to analyze document using the search index \"{}\": {}", req.index_name, resp.error));
3566
+ }
3567
+ break;
3568
+ }
3569
+ VALUE res = rb_hash_new();
3570
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), rb_str_new(resp.status.data(), static_cast<long>(resp.status.size())));
3571
+ rb_hash_aset(res, rb_id2sym(rb_intern("analysis")), rb_str_new(resp.analysis.data(), static_cast<long>(resp.analysis.size())));
3572
+ return res;
3573
+ } while (false);
3574
+ rb_exc_raise(exc);
3575
+ return Qnil;
3576
+ }
3577
+
3578
+ static VALUE
3579
+ cb_Backend_document_search(VALUE self, VALUE index_name, VALUE query, VALUE options)
3580
+ {
3581
+ cb_backend_data* backend = nullptr;
3582
+ TypedData_Get_Struct(self, cb_backend_data, &cb_backend_type, backend);
3583
+
3584
+ if (!backend->cluster) {
3585
+ rb_raise(rb_eArgError, "Cluster has been closed already");
3586
+ }
3587
+
3588
+ Check_Type(index_name, T_STRING);
3589
+ Check_Type(query, T_STRING);
3590
+ Check_Type(options, T_HASH);
3591
+
3592
+ VALUE exc = Qnil;
3593
+ do {
3594
+ couchbase::operations::search_request req;
3595
+ VALUE client_context_id = rb_hash_aref(options, rb_id2sym(rb_intern("client_context_id")));
3596
+ if (!NIL_P(client_context_id)) {
3597
+ Check_Type(client_context_id, T_STRING);
3598
+ req.client_context_id.assign(RSTRING_PTR(client_context_id), static_cast<size_t>(RSTRING_LEN(client_context_id)));
3599
+ }
3600
+ cb__extract_timeout(req, rb_hash_aref(options, rb_id2sym(rb_intern("timeout"))));
3601
+ req.index_name.assign(RSTRING_PTR(index_name), static_cast<size_t>(RSTRING_LEN(index_name)));
3602
+ req.query = tao::json::from_string(std::string(RSTRING_PTR(query), static_cast<size_t>(RSTRING_LEN(query))));
3603
+
3604
+ VALUE explain = rb_hash_aref(options, rb_id2sym(rb_intern("explain")));
3605
+ if (!NIL_P(explain)) {
3606
+ req.explain = RTEST(explain);
3607
+ }
3608
+
3609
+ VALUE skip = rb_hash_aref(options, rb_id2sym(rb_intern("skip")));
3610
+ if (!NIL_P(skip)) {
3611
+ Check_Type(skip, T_FIXNUM);
3612
+ req.skip = FIX2ULONG(skip);
3613
+ }
3614
+
3615
+ VALUE limit = rb_hash_aref(options, rb_id2sym(rb_intern("limit")));
3616
+ if (!NIL_P(limit)) {
3617
+ Check_Type(limit, T_FIXNUM);
3618
+ req.limit = FIX2ULONG(limit);
3619
+ }
3620
+
3621
+ VALUE highlight_style = rb_hash_aref(options, rb_id2sym(rb_intern("highlight_style")));
3622
+ if (!NIL_P(highlight_style)) {
3623
+ Check_Type(highlight_style, T_SYMBOL);
3624
+ ID type = rb_sym2id(highlight_style);
3625
+ if (type == rb_intern("html")) {
3626
+ req.highlight_style = couchbase::operations::search_request::highlight_style_type::html;
3627
+ } else if (type == rb_intern("ansi")) {
3628
+ req.highlight_style = couchbase::operations::search_request::highlight_style_type::ansi;
3629
+ }
3630
+ }
3631
+
3632
+ VALUE highlight_fields = rb_hash_aref(options, rb_id2sym(rb_intern("highlight_fields")));
3633
+ if (!NIL_P(highlight_fields)) {
3634
+ Check_Type(highlight_fields, T_ARRAY);
3635
+ auto highlight_fields_size = static_cast<size_t>(RARRAY_LEN(highlight_fields));
3636
+ req.highlight_fields.reserve(highlight_fields_size);
3637
+ for (size_t i = 0; i < highlight_fields_size; ++i) {
3638
+ VALUE field = rb_ary_entry(highlight_fields, static_cast<long>(i));
3639
+ Check_Type(field, T_STRING);
3640
+ req.highlight_fields.emplace_back(std::string(RSTRING_PTR(field), static_cast<std::size_t>(RSTRING_LEN(field))));
3641
+ }
3642
+ }
3643
+
3644
+ VALUE scan_consistency = rb_hash_aref(options, rb_id2sym(rb_intern("scan_consistency")));
3645
+ if (!NIL_P(scan_consistency)) {
3646
+ Check_Type(scan_consistency, T_SYMBOL);
3647
+ ID type = rb_sym2id(scan_consistency);
3648
+ if (type == rb_intern("not_bounded")) {
3649
+ req.scan_consistency = couchbase::operations::search_request::scan_consistency_type::not_bounded;
3650
+ }
3651
+ }
3652
+
3653
+ VALUE mutation_state = rb_hash_aref(options, rb_id2sym(rb_intern("mutation_state")));
3654
+ if (!NIL_P(mutation_state)) {
3655
+ Check_Type(mutation_state, T_ARRAY);
3656
+ auto state_size = static_cast<size_t>(RARRAY_LEN(mutation_state));
3657
+ req.mutation_state.reserve(state_size);
3658
+ for (size_t i = 0; i < state_size; ++i) {
3659
+ VALUE token = rb_ary_entry(mutation_state, static_cast<long>(i));
3660
+ Check_Type(token, T_HASH);
3661
+ VALUE bucket_name = rb_hash_aref(token, rb_id2sym(rb_intern("bucket_name")));
3662
+ Check_Type(bucket_name, T_STRING);
3663
+ VALUE partition_id = rb_hash_aref(token, rb_id2sym(rb_intern("partition_id")));
3664
+ Check_Type(partition_id, T_FIXNUM);
3665
+ VALUE partition_uuid = rb_hash_aref(token, rb_id2sym(rb_intern("partition_uuid")));
3666
+ switch (TYPE(partition_uuid)) {
3667
+ case T_FIXNUM:
3668
+ case T_BIGNUM:
3669
+ break;
3670
+ default:
3671
+ rb_raise(rb_eArgError, "partition_uuid must be an Integer");
3672
+ }
3673
+ VALUE sequence_number = rb_hash_aref(token, rb_id2sym(rb_intern("sequence_number")));
3674
+ switch (TYPE(sequence_number)) {
3675
+ case T_FIXNUM:
3676
+ case T_BIGNUM:
3677
+ break;
3678
+ default:
3679
+ rb_raise(rb_eArgError, "sequence_number must be an Integer");
3680
+ }
3681
+ req.mutation_state.emplace_back(
3682
+ couchbase::mutation_token{ NUM2ULL(partition_uuid),
3683
+ NUM2ULL(sequence_number),
3684
+ gsl::narrow_cast<std::uint16_t>(NUM2UINT(partition_id)),
3685
+ std::string(RSTRING_PTR(bucket_name), static_cast<std::size_t>(RSTRING_LEN(bucket_name))) });
3686
+ }
3687
+ }
3688
+
3689
+ VALUE fields = rb_hash_aref(options, rb_id2sym(rb_intern("fields")));
3690
+ if (!NIL_P(fields)) {
3691
+ Check_Type(fields, T_ARRAY);
3692
+ auto fields_size = static_cast<size_t>(RARRAY_LEN(fields));
3693
+ req.fields.reserve(fields_size);
3694
+ for (size_t i = 0; i < fields_size; ++i) {
3695
+ VALUE field = rb_ary_entry(fields, static_cast<long>(i));
3696
+ Check_Type(field, T_STRING);
3697
+ req.fields.emplace_back(std::string(RSTRING_PTR(field), static_cast<std::size_t>(RSTRING_LEN(field))));
3698
+ }
3699
+ }
3700
+
3701
+ VALUE sort = rb_hash_aref(options, rb_id2sym(rb_intern("sort")));
3702
+ if (!NIL_P(sort)) {
3703
+ Check_Type(sort, T_ARRAY);
3704
+ for (size_t i = 0; i < static_cast<std::size_t>(RARRAY_LEN(sort)); ++i) {
3705
+ VALUE sort_spec = rb_ary_entry(sort, static_cast<long>(i));
3706
+ req.sort_specs.emplace_back(std::string(RSTRING_PTR(sort_spec), static_cast<std::size_t>(RSTRING_LEN(sort_spec))));
3707
+ }
3708
+ }
3709
+
3710
+ VALUE facets = rb_hash_aref(options, rb_id2sym(rb_intern("facets")));
3711
+ if (!NIL_P(facets)) {
3712
+ Check_Type(facets, T_ARRAY);
3713
+ for (size_t i = 0; i < static_cast<std::size_t>(RARRAY_LEN(facets)); ++i) {
3714
+ VALUE facet_pair = rb_ary_entry(facets, static_cast<long>(i));
3715
+ Check_Type(facet_pair, T_ARRAY);
3716
+ if (RARRAY_LEN(facet_pair) == 2) {
3717
+ VALUE facet_name = rb_ary_entry(facet_pair, 0);
3718
+ Check_Type(facet_name, T_STRING);
3719
+ VALUE facet_definition = rb_ary_entry(facet_pair, 1);
3720
+ Check_Type(facet_definition, T_STRING);
3721
+ req.facets.emplace(std::string(RSTRING_PTR(facet_name), static_cast<std::size_t>(RSTRING_LEN(facet_name))),
3722
+ std::string(RSTRING_PTR(facet_definition), static_cast<std::size_t>(RSTRING_LEN(facet_definition))));
3723
+ }
3724
+ }
3725
+ }
3726
+
3727
+ VALUE raw_params = rb_hash_aref(options, rb_id2sym(rb_intern("raw_parameters")));
3728
+ if (!NIL_P(raw_params)) {
3729
+ Check_Type(raw_params, T_HASH);
3730
+ rb_hash_foreach(raw_params, INT_FUNC(cb__for_each_named_param), reinterpret_cast<VALUE>(&req));
3731
+ }
3732
+
3733
+ auto barrier = std::make_shared<std::promise<couchbase::operations::search_response>>();
3734
+ auto f = barrier->get_future();
3735
+ backend->cluster->execute_http(req, [barrier](couchbase::operations::search_response resp) mutable { barrier->set_value(resp); });
3736
+ auto resp = f.get();
3737
+ if (resp.ec) {
3738
+ exc = cb__map_error_code(resp.ec, fmt::format("unable to perform search query for index \"{}\"", req.index_name));
3739
+ break;
3740
+ }
3741
+ VALUE res = rb_hash_new();
3742
+
3743
+ VALUE meta_data = rb_hash_new();
3744
+ rb_hash_aset(meta_data,
3745
+ rb_id2sym(rb_intern("client_context_id")),
3746
+ rb_str_new(resp.meta_data.client_context_id.data(), static_cast<long>(resp.meta_data.client_context_id.size())));
3747
+
3748
+ VALUE metrics = rb_hash_new();
3749
+ rb_hash_aset(metrics,
3750
+ rb_id2sym(rb_intern("took")),
3751
+ LONG2NUM(std::chrono::duration_cast<std::chrono::milliseconds>(resp.meta_data.metrics.took).count()));
3752
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("total_rows")), ULL2NUM(resp.meta_data.metrics.total_rows));
3753
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("max_score")), DBL2NUM(resp.meta_data.metrics.max_score));
3754
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("success_partition_count")), ULL2NUM(resp.meta_data.metrics.success_partition_count));
3755
+ rb_hash_aset(metrics, rb_id2sym(rb_intern("error_partition_count")), ULL2NUM(resp.meta_data.metrics.error_partition_count));
3756
+ rb_hash_aset(meta_data, rb_id2sym(rb_intern("metrics")), metrics);
3757
+
3758
+ if (!resp.meta_data.errors.empty()) {
3759
+ VALUE errors = rb_hash_new();
3760
+ for (auto err : resp.meta_data.errors) {
3761
+ rb_hash_aset(errors,
3762
+ rb_str_new(err.first.data(), static_cast<long>(err.first.size())),
3763
+ rb_str_new(err.second.data(), static_cast<long>(err.second.size())));
3764
+ }
3765
+ rb_hash_aset(meta_data, rb_id2sym(rb_intern("errors")), errors);
3766
+ }
3767
+
3768
+ rb_hash_aset(res, rb_id2sym(rb_intern("meta_data")), meta_data);
3769
+
3770
+ VALUE rows = rb_ary_new_capa(static_cast<long>(resp.rows.size()));
3771
+ for (const auto& entry : resp.rows) {
3772
+ VALUE row = rb_hash_new();
3773
+ rb_hash_aset(row, rb_id2sym(rb_intern("index")), rb_str_new(entry.index.data(), static_cast<long>(entry.index.size())));
3774
+ rb_hash_aset(row, rb_id2sym(rb_intern("id")), rb_str_new(entry.id.data(), static_cast<long>(entry.id.size())));
3775
+ rb_hash_aset(row, rb_id2sym(rb_intern("score")), DBL2NUM(entry.score));
3776
+ VALUE locations = rb_ary_new_capa(static_cast<long>(entry.locations.size()));
3777
+ for (const auto& loc : entry.locations) {
3778
+ VALUE location = rb_hash_new();
3779
+ rb_hash_aset(row, rb_id2sym(rb_intern("field")), rb_str_new(loc.field.data(), static_cast<long>(loc.field.size())));
3780
+ rb_hash_aset(row, rb_id2sym(rb_intern("term")), rb_str_new(loc.term.data(), static_cast<long>(loc.term.size())));
3781
+ rb_hash_aset(row, rb_id2sym(rb_intern("pos")), ULL2NUM(loc.position));
3782
+ rb_hash_aset(row, rb_id2sym(rb_intern("start_offset")), ULL2NUM(loc.start_offset));
3783
+ rb_hash_aset(row, rb_id2sym(rb_intern("end_offset")), ULL2NUM(loc.end_offset));
3784
+ if (loc.array_positions) {
3785
+ VALUE ap = rb_ary_new_capa(static_cast<long>(loc.array_positions->size()));
3786
+ for (const auto& pos : *loc.array_positions) {
3787
+ rb_ary_push(ap, ULL2NUM(pos));
3788
+ }
3789
+ rb_hash_aset(row, rb_id2sym(rb_intern("array_positions")), ap);
3790
+ }
3791
+ rb_ary_push(locations, location);
3792
+ }
3793
+ rb_hash_aset(row, rb_id2sym(rb_intern("locations")), locations);
3794
+ if (!entry.fragments.empty()) {
3795
+ VALUE fragments = rb_hash_new();
3796
+ for (const auto& field_fragments : entry.fragments) {
3797
+ VALUE fragments_list = rb_ary_new_capa(static_cast<long>(field_fragments.second.size()));
3798
+ for (const auto& fragment : field_fragments.second) {
3799
+ rb_ary_push(fragments_list, rb_str_new(fragment.data(), static_cast<long>(fragment.size())));
3800
+ }
3801
+ rb_hash_aset(
3802
+ fragments, rb_str_new(field_fragments.first.data(), static_cast<long>(field_fragments.first.size())), fragments_list);
3803
+ }
3804
+ rb_hash_aset(row, rb_id2sym(rb_intern("fragments")), fragments);
3805
+ }
3806
+ if (!entry.fields.empty()) {
3807
+ rb_hash_aset(row, rb_id2sym(rb_intern("fields")), rb_str_new(entry.fields.data(), static_cast<long>(entry.fields.size())));
3808
+ }
3809
+ if (!entry.explanation.empty()) {
3810
+ rb_hash_aset(row,
3811
+ rb_id2sym(rb_intern("explanation")),
3812
+ rb_str_new(entry.explanation.data(), static_cast<long>(entry.explanation.size())));
3813
+ }
3814
+ rb_ary_push(rows, row);
3815
+ }
3816
+ rb_hash_aset(res, rb_id2sym(rb_intern("rows")), rows);
3817
+
3818
+ if (!resp.facets.empty()) {
3819
+ VALUE result_facets = rb_hash_new();
3820
+ for (const auto& entry : resp.facets) {
3821
+ VALUE facet = rb_hash_new();
3822
+ VALUE facet_name = rb_str_new(entry.name.data(), static_cast<long>(entry.name.size()));
3823
+ rb_hash_aset(facet, rb_id2sym(rb_intern("name")), facet_name);
3824
+ rb_hash_aset(facet, rb_id2sym(rb_intern("field")), rb_str_new(entry.field.data(), static_cast<long>(entry.field.size())));
3825
+ rb_hash_aset(facet, rb_id2sym(rb_intern("total")), ULL2NUM(entry.total));
3826
+ rb_hash_aset(facet, rb_id2sym(rb_intern("missing")), ULL2NUM(entry.missing));
3827
+ rb_hash_aset(facet, rb_id2sym(rb_intern("other")), ULL2NUM(entry.other));
3828
+ if (!entry.terms.empty()) {
3829
+ VALUE terms = rb_ary_new_capa(static_cast<long>(entry.terms.size()));
3830
+ for (const auto& item : entry.terms) {
3831
+ VALUE term = rb_hash_new();
3832
+ rb_hash_aset(term, rb_id2sym(rb_intern("term")), rb_str_new(item.term.data(), static_cast<long>(item.term.size())));
3833
+ rb_hash_aset(term, rb_id2sym(rb_intern("count")), ULL2NUM(item.count));
3834
+ rb_ary_push(terms, term);
3835
+ }
3836
+ rb_hash_aset(facet, rb_id2sym(rb_intern("terms")), terms);
3837
+ } else if (!entry.date_ranges.empty()) {
3838
+ VALUE date_ranges = rb_ary_new_capa(static_cast<long>(entry.date_ranges.size()));
3839
+ for (const auto& item : entry.date_ranges) {
3840
+ VALUE date_range = rb_hash_new();
3841
+ rb_hash_aset(
3842
+ date_range, rb_id2sym(rb_intern("name")), rb_str_new(item.name.data(), static_cast<long>(item.name.size())));
3843
+ rb_hash_aset(date_range, rb_id2sym(rb_intern("count")), ULL2NUM(item.count));
3844
+ if (item.start) {
3845
+ rb_hash_aset(date_range,
3846
+ rb_id2sym(rb_intern("start_time")),
3847
+ rb_str_new(item.start->data(), static_cast<long>(item.start->size())));
3848
+ }
3849
+ if (item.end) {
3850
+ rb_hash_aset(date_range,
3851
+ rb_id2sym(rb_intern("end_time")),
3852
+ rb_str_new(item.end->data(), static_cast<long>(item.end->size())));
3853
+ }
3854
+ rb_ary_push(date_ranges, date_range);
3855
+ }
3856
+ rb_hash_aset(facet, rb_id2sym(rb_intern("date_ranges")), date_ranges);
3857
+ } else if (!entry.numeric_ranges.empty()) {
3858
+ VALUE numeric_ranges = rb_ary_new_capa(static_cast<long>(entry.numeric_ranges.size()));
3859
+ for (const auto& item : entry.numeric_ranges) {
3860
+ VALUE numeric_range = rb_hash_new();
3861
+ rb_hash_aset(
3862
+ numeric_range, rb_id2sym(rb_intern("name")), rb_str_new(item.name.data(), static_cast<long>(item.name.size())));
3863
+ rb_hash_aset(numeric_range, rb_id2sym(rb_intern("count")), ULL2NUM(item.count));
3864
+ if (std::holds_alternative<double>(item.min)) {
3865
+ rb_hash_aset(numeric_range, rb_id2sym(rb_intern("min")), DBL2NUM(std::get<double>(item.min)));
3866
+ } else if (std::holds_alternative<std::uint64_t>(item.min)) {
3867
+ rb_hash_aset(numeric_range, rb_id2sym(rb_intern("min")), ULL2NUM(std::get<std::uint64_t>(item.min)));
3868
+ }
3869
+ if (std::holds_alternative<double>(item.max)) {
3870
+ rb_hash_aset(numeric_range, rb_id2sym(rb_intern("max")), DBL2NUM(std::get<double>(item.max)));
3871
+ } else if (std::holds_alternative<std::uint64_t>(item.max)) {
3872
+ rb_hash_aset(numeric_range, rb_id2sym(rb_intern("max")), ULL2NUM(std::get<std::uint64_t>(item.max)));
3873
+ }
3874
+ rb_ary_push(numeric_ranges, numeric_range);
3875
+ }
3876
+ rb_hash_aset(facet, rb_id2sym(rb_intern("numeric_ranges")), numeric_ranges);
3877
+ }
3878
+ rb_hash_aset(result_facets, facet_name, facet);
3879
+ }
3880
+ rb_hash_aset(res, rb_id2sym(rb_intern("facets")), result_facets);
3881
+ }
3882
+
3883
+ return res;
3884
+ } while (false);
3885
+ rb_exc_raise(exc);
3886
+ return Qnil;
3887
+ }
3888
+
3889
+ static void
3890
+ init_backend(VALUE mCouchbase)
3891
+ {
3892
+ VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cBasicObject);
3893
+ rb_define_alloc_func(cBackend, cb_Backend_allocate);
3894
+ rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open), 3);
3895
+ rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
3896
+ rb_define_method(cBackend, "open_bucket", VALUE_FUNC(cb_Backend_open_bucket), 1);
3897
+
3898
+ rb_define_method(cBackend, "document_get", VALUE_FUNC(cb_Backend_document_get), 4);
3899
+ rb_define_method(cBackend, "document_get_projected", VALUE_FUNC(cb_Backend_document_get_projected), 7);
3900
+ rb_define_method(cBackend, "document_get_and_lock", VALUE_FUNC(cb_Backend_document_get_and_lock), 5);
3901
+ rb_define_method(cBackend, "document_get_and_touch", VALUE_FUNC(cb_Backend_document_get_and_touch), 5);
3902
+ rb_define_method(cBackend, "document_insert", VALUE_FUNC(cb_Backend_document_insert), 7);
3903
+ rb_define_method(cBackend, "document_replace", VALUE_FUNC(cb_Backend_document_replace), 7);
3904
+ rb_define_method(cBackend, "document_upsert", VALUE_FUNC(cb_Backend_document_upsert), 7);
3905
+ rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 5);
3906
+ rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 6);
3907
+ rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 7);
3908
+ rb_define_method(cBackend, "document_query", VALUE_FUNC(cb_Backend_document_query), 2);
3909
+ rb_define_method(cBackend, "document_touch", VALUE_FUNC(cb_Backend_document_touch), 5);
3910
+ rb_define_method(cBackend, "document_exists", VALUE_FUNC(cb_Backend_document_exists), 4);
3911
+ rb_define_method(cBackend, "document_unlock", VALUE_FUNC(cb_Backend_document_unlock), 5);
3912
+ rb_define_method(cBackend, "document_increment", VALUE_FUNC(cb_Backend_document_increment), 5);
3913
+ rb_define_method(cBackend, "document_decrement", VALUE_FUNC(cb_Backend_document_decrement), 5);
3914
+ rb_define_method(cBackend, "document_search", VALUE_FUNC(cb_Backend_document_search), 3);
3915
+
3916
+ rb_define_method(cBackend, "bucket_create", VALUE_FUNC(cb_Backend_bucket_create), 2);
3917
+ rb_define_method(cBackend, "bucket_update", VALUE_FUNC(cb_Backend_bucket_update), 2);
3918
+ rb_define_method(cBackend, "bucket_drop", VALUE_FUNC(cb_Backend_bucket_drop), 2);
3919
+ rb_define_method(cBackend, "bucket_flush", VALUE_FUNC(cb_Backend_bucket_flush), 2);
3920
+ rb_define_method(cBackend, "bucket_get_all", VALUE_FUNC(cb_Backend_bucket_get_all), 1);
3921
+ rb_define_method(cBackend, "bucket_get", VALUE_FUNC(cb_Backend_bucket_get), 2);
3922
+
3923
+ rb_define_method(cBackend, "cluster_enable_developer_preview!", VALUE_FUNC(cb_Backend_cluster_enable_developer_preview), 0);
3924
+
3925
+ rb_define_method(cBackend, "scope_get_all", VALUE_FUNC(cb_Backend_scope_get_all), 2);
3926
+ rb_define_method(cBackend, "scope_create", VALUE_FUNC(cb_Backend_scope_create), 3);
3927
+ rb_define_method(cBackend, "scope_drop", VALUE_FUNC(cb_Backend_scope_drop), 3);
3928
+ rb_define_method(cBackend, "collection_create", VALUE_FUNC(cb_Backend_collection_create), 5);
3929
+ rb_define_method(cBackend, "collection_drop", VALUE_FUNC(cb_Backend_collection_drop), 4);
3930
+
3931
+ rb_define_method(cBackend, "query_index_get_all", VALUE_FUNC(cb_Backend_query_index_get_all), 2);
3932
+ rb_define_method(cBackend, "query_index_create", VALUE_FUNC(cb_Backend_query_index_create), 5);
3933
+ rb_define_method(cBackend, "query_index_create_primary", VALUE_FUNC(cb_Backend_query_index_create_primary), 3);
3934
+ rb_define_method(cBackend, "query_index_drop", VALUE_FUNC(cb_Backend_query_index_drop), 4);
3935
+ rb_define_method(cBackend, "query_index_drop_primary", VALUE_FUNC(cb_Backend_query_index_drop_primary), 3);
3936
+ rb_define_method(cBackend, "query_index_build_deferred", VALUE_FUNC(cb_Backend_query_index_build_deferred), 2);
3937
+ rb_define_method(cBackend, "query_index_watch", VALUE_FUNC(cb_Backend_query_index_watch), 4);
3938
+
3939
+ rb_define_method(cBackend, "search_index_get_all", VALUE_FUNC(cb_Backend_search_index_get_all), 1);
3940
+ rb_define_method(cBackend, "search_index_get", VALUE_FUNC(cb_Backend_search_index_get), 2);
3941
+ rb_define_method(cBackend, "search_index_upsert", VALUE_FUNC(cb_Backend_search_index_upsert), 2);
3942
+ rb_define_method(cBackend, "search_index_drop", VALUE_FUNC(cb_Backend_search_index_drop), 2);
3943
+ rb_define_method(cBackend, "search_index_get_documents_count", VALUE_FUNC(cb_Backend_search_index_get_documents_count), 2);
3944
+ rb_define_method(cBackend, "search_index_pause_ingest", VALUE_FUNC(cb_Backend_search_index_pause_ingest), 2);
3945
+ rb_define_method(cBackend, "search_index_resume_ingest", VALUE_FUNC(cb_Backend_search_index_resume_ingest), 2);
3946
+ rb_define_method(cBackend, "search_index_allow_querying", VALUE_FUNC(cb_Backend_search_index_allow_querying), 2);
3947
+ rb_define_method(cBackend, "search_index_disallow_querying", VALUE_FUNC(cb_Backend_search_index_disallow_querying), 2);
3948
+ rb_define_method(cBackend, "search_index_freeze_plan", VALUE_FUNC(cb_Backend_search_index_freeze_plan), 2);
3949
+ rb_define_method(cBackend, "search_index_unfreeze_plan", VALUE_FUNC(cb_Backend_search_index_unfreeze_plan), 2);
3950
+ rb_define_method(cBackend, "search_index_analyze_document", VALUE_FUNC(cb_Backend_search_index_analyze_document), 3);
2741
3951
  }
2742
3952
 
2743
3953
  extern "C" {