couchbase 3.0.0.alpha.2-universal-darwin-19 → 3.0.0.alpha.3-universal-darwin-19

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