couchbase 3.4.2 → 3.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +71 -7
  4. data/ext/couchbase/cmake/Documentation.cmake +0 -1
  5. data/ext/couchbase/cmake/OpenSSL.cmake +98 -3
  6. data/ext/couchbase/cmake/Testing.cmake +12 -4
  7. data/ext/couchbase/cmake/build_config.hxx.in +3 -0
  8. data/ext/couchbase/core/bucket.cxx +183 -151
  9. data/ext/couchbase/core/bucket.hxx +23 -1
  10. data/ext/couchbase/core/cluster.hxx +51 -13
  11. data/ext/couchbase/core/cluster_options.cxx +2 -2
  12. data/ext/couchbase/core/cluster_options.hxx +7 -6
  13. data/ext/couchbase/core/cluster_options_fwd.hxx +26 -0
  14. data/ext/couchbase/core/config_profile.hxx +1 -54
  15. data/ext/couchbase/core/config_profiles.cxx +79 -0
  16. data/ext/couchbase/core/config_profiles.hxx +56 -0
  17. data/ext/couchbase/core/crud_component.cxx +51 -22
  18. data/ext/couchbase/core/error_context/key_value.cxx +2 -1
  19. data/ext/couchbase/core/error_context/key_value.hxx +10 -12
  20. data/ext/couchbase/core/error_context/search.hxx +1 -1
  21. data/ext/couchbase/core/impl/analytics.cxx +1 -0
  22. data/ext/couchbase/core/impl/boolean_field_query.cxx +40 -0
  23. data/ext/couchbase/core/impl/boolean_query.cxx +62 -0
  24. data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
  25. data/ext/couchbase/core/impl/cluster.cxx +8 -0
  26. data/ext/couchbase/core/impl/conjunction_query.cxx +51 -0
  27. data/ext/couchbase/core/impl/create_bucket.cxx +155 -0
  28. data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
  29. data/ext/couchbase/core/impl/date_range.cxx +89 -0
  30. data/ext/couchbase/core/impl/date_range_facet.cxx +54 -0
  31. data/ext/couchbase/core/impl/date_range_facet_result.cxx +64 -0
  32. data/ext/couchbase/core/impl/date_range_query.cxx +125 -0
  33. data/ext/couchbase/core/impl/disjunction_query.cxx +51 -0
  34. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
  35. data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
  36. data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
  37. data/ext/couchbase/core/impl/encoded_search_facet.hxx +29 -0
  38. data/ext/couchbase/core/impl/encoded_search_query.hxx +29 -0
  39. data/ext/couchbase/core/impl/encoded_search_sort.hxx +29 -0
  40. data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
  41. data/ext/couchbase/core/impl/geo_bounding_box_query.cxx +46 -0
  42. data/ext/couchbase/core/impl/geo_distance_query.cxx +43 -0
  43. data/ext/couchbase/core/impl/geo_polygon_query.cxx +46 -0
  44. data/ext/couchbase/core/impl/get_all_buckets.cxx +163 -0
  45. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
  46. data/ext/couchbase/core/impl/get_bucket.cxx +153 -0
  47. data/ext/couchbase/core/impl/internal_date_range_facet_result.cxx +80 -0
  48. data/ext/couchbase/core/impl/internal_date_range_facet_result.hxx +48 -0
  49. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
  50. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
  51. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.cxx +80 -0
  52. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.hxx +48 -0
  53. data/ext/couchbase/core/impl/internal_search_error_context.cxx +141 -0
  54. data/ext/couchbase/core/impl/internal_search_error_context.hxx +61 -0
  55. data/ext/couchbase/core/impl/internal_search_meta_data.cxx +60 -0
  56. data/ext/couchbase/core/impl/internal_search_meta_data.hxx +41 -0
  57. data/ext/couchbase/core/impl/internal_search_result.cxx +84 -0
  58. data/ext/couchbase/core/impl/internal_search_result.hxx +43 -0
  59. data/ext/couchbase/core/impl/internal_search_row.cxx +82 -0
  60. data/ext/couchbase/core/impl/internal_search_row.hxx +56 -0
  61. data/ext/couchbase/core/impl/internal_search_row_location.hxx +32 -0
  62. data/ext/couchbase/core/impl/internal_search_row_locations.cxx +137 -0
  63. data/ext/couchbase/core/impl/internal_search_row_locations.hxx +45 -0
  64. data/ext/couchbase/core/impl/internal_term_facet_result.cxx +80 -0
  65. data/ext/couchbase/core/impl/internal_term_facet_result.hxx +48 -0
  66. data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
  67. data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
  68. data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
  69. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +176 -0
  70. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
  71. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +167 -0
  72. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
  73. data/ext/couchbase/core/impl/lookup_in_replica.cxx +97 -0
  74. data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
  75. data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
  76. data/ext/couchbase/core/impl/match_all_query.cxx +35 -0
  77. data/ext/couchbase/core/impl/match_none_query.cxx +35 -0
  78. data/ext/couchbase/core/impl/match_phrase_query.cxx +43 -0
  79. data/ext/couchbase/core/impl/match_query.cxx +59 -0
  80. data/ext/couchbase/core/impl/numeric_range.cxx +49 -0
  81. data/ext/couchbase/core/impl/numeric_range_facet.cxx +54 -0
  82. data/ext/couchbase/core/impl/numeric_range_facet_result.cxx +64 -0
  83. data/ext/couchbase/core/impl/numeric_range_query.cxx +56 -0
  84. data/ext/couchbase/core/impl/phrase_query.cxx +42 -0
  85. data/ext/couchbase/core/impl/prefix_query.cxx +40 -0
  86. data/ext/couchbase/core/impl/query.cxx +1 -0
  87. data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
  88. data/ext/couchbase/core/impl/query_string_query.cxx +37 -0
  89. data/ext/couchbase/core/impl/regexp_query.cxx +40 -0
  90. data/ext/couchbase/core/impl/search.cxx +191 -0
  91. data/ext/couchbase/core/impl/search_error_context.cxx +147 -0
  92. data/ext/couchbase/core/impl/search_meta_data.cxx +46 -0
  93. data/ext/couchbase/core/impl/search_result.cxx +66 -0
  94. data/ext/couchbase/core/impl/search_row.cxx +74 -0
  95. data/ext/couchbase/core/impl/search_row_location.cxx +64 -0
  96. data/ext/couchbase/core/impl/search_row_locations.cxx +66 -0
  97. data/ext/couchbase/core/impl/search_sort_field.cxx +104 -0
  98. data/ext/couchbase/core/impl/search_sort_id.cxx +43 -0
  99. data/ext/couchbase/core/impl/search_sort_score.cxx +43 -0
  100. data/ext/couchbase/core/impl/term_facet.cxx +36 -0
  101. data/ext/couchbase/core/impl/term_facet_result.cxx +64 -0
  102. data/ext/couchbase/core/impl/term_query.cxx +56 -0
  103. data/ext/couchbase/core/impl/term_range_query.cxx +57 -0
  104. data/ext/couchbase/core/impl/update_bucket.cxx +130 -0
  105. data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
  106. data/ext/couchbase/core/impl/wildcard_query.cxx +40 -0
  107. data/ext/couchbase/core/io/dns_client.cxx +111 -40
  108. data/ext/couchbase/core/io/dns_config.cxx +5 -4
  109. data/ext/couchbase/core/io/http_context.hxx +1 -1
  110. data/ext/couchbase/core/io/http_session.hxx +34 -1
  111. data/ext/couchbase/core/io/http_session_manager.hxx +5 -3
  112. data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
  113. data/ext/couchbase/core/io/mcbp_session.cxx +106 -42
  114. data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
  115. data/ext/couchbase/core/io/retry_orchestrator.hxx +3 -2
  116. data/ext/couchbase/core/json_string.hxx +5 -0
  117. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
  118. data/ext/couchbase/core/logger/logger.cxx +80 -20
  119. data/ext/couchbase/core/logger/logger.hxx +31 -0
  120. data/ext/couchbase/core/meta/features.hxx +25 -0
  121. data/ext/couchbase/core/meta/version.cxx +18 -4
  122. data/ext/couchbase/core/mozilla_ca_bundle.hxx +39 -0
  123. data/ext/couchbase/core/operations/document_analytics.cxx +1 -0
  124. data/ext/couchbase/core/operations/document_analytics.hxx +1 -0
  125. data/ext/couchbase/core/operations/document_append.hxx +1 -1
  126. data/ext/couchbase/core/operations/document_decrement.hxx +1 -1
  127. data/ext/couchbase/core/operations/document_exists.hxx +1 -1
  128. data/ext/couchbase/core/operations/document_get.hxx +1 -1
  129. data/ext/couchbase/core/operations/document_get_and_lock.hxx +1 -1
  130. data/ext/couchbase/core/operations/document_get_and_touch.hxx +1 -1
  131. data/ext/couchbase/core/operations/document_get_projected.hxx +1 -1
  132. data/ext/couchbase/core/operations/document_increment.hxx +1 -1
  133. data/ext/couchbase/core/operations/document_insert.hxx +1 -1
  134. data/ext/couchbase/core/operations/document_lookup_in.hxx +1 -1
  135. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  136. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
  137. data/ext/couchbase/core/operations/document_mutate_in.hxx +1 -1
  138. data/ext/couchbase/core/operations/document_prepend.hxx +1 -1
  139. data/ext/couchbase/core/operations/document_query.cxx +13 -0
  140. data/ext/couchbase/core/operations/document_query.hxx +7 -0
  141. data/ext/couchbase/core/operations/document_remove.hxx +1 -1
  142. data/ext/couchbase/core/operations/document_replace.hxx +1 -1
  143. data/ext/couchbase/core/operations/document_search.cxx +4 -1
  144. data/ext/couchbase/core/operations/document_search.hxx +2 -1
  145. data/ext/couchbase/core/operations/document_touch.hxx +1 -1
  146. data/ext/couchbase/core/operations/document_unlock.hxx +1 -1
  147. data/ext/couchbase/core/operations/document_upsert.hxx +1 -1
  148. data/ext/couchbase/core/operations/document_view.hxx +1 -0
  149. data/ext/couchbase/core/operations.hxx +2 -0
  150. data/ext/couchbase/core/origin.cxx +270 -0
  151. data/ext/couchbase/core/origin.hxx +2 -0
  152. data/ext/couchbase/core/protocol/client_request.hxx +11 -2
  153. data/ext/couchbase/core/protocol/client_response.hxx +1 -0
  154. data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
  155. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  156. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  157. data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
  158. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
  159. data/ext/couchbase/core/protocol/status.cxx +2 -2
  160. data/ext/couchbase/core/public_fwd.hxx +21 -0
  161. data/ext/couchbase/core/range_scan_options.cxx +3 -27
  162. data/ext/couchbase/core/range_scan_options.hxx +13 -17
  163. data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
  164. data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
  165. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
  166. data/ext/couchbase/core/scan_options.hxx +0 -19
  167. data/ext/couchbase/core/scan_result.cxx +19 -5
  168. data/ext/couchbase/core/scan_result.hxx +5 -2
  169. data/ext/couchbase/core/timeout_defaults.hxx +2 -3
  170. data/ext/couchbase/core/tls_verify_mode.hxx +26 -0
  171. data/ext/couchbase/core/topology/capabilities.hxx +3 -0
  172. data/ext/couchbase/core/topology/capabilities_fmt.hxx +8 -0
  173. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
  174. data/ext/couchbase/core/topology/configuration.cxx +15 -2
  175. data/ext/couchbase/core/topology/configuration.hxx +20 -1
  176. data/ext/couchbase/core/topology/configuration_json.hxx +6 -1
  177. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.cxx +93 -0
  178. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.hxx +48 -75
  179. data/ext/couchbase/core/transactions/cleanup_testing_hooks.cxx +52 -0
  180. data/ext/couchbase/core/transactions/cleanup_testing_hooks.hxx +17 -31
  181. data/ext/couchbase/core/transactions/exceptions.hxx +12 -9
  182. data/ext/couchbase/core/utils/connection_string.cxx +75 -43
  183. data/ext/couchbase/core/utils/connection_string.hxx +1 -0
  184. data/ext/couchbase/core/utils/json.cxx +4 -1
  185. data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
  186. data/ext/couchbase/couchbase/behavior_options.hxx +27 -1
  187. data/ext/couchbase/couchbase/boolean_field_query.hxx +77 -0
  188. data/ext/couchbase/couchbase/boolean_query.hxx +223 -0
  189. data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
  190. data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
  191. data/ext/couchbase/couchbase/cluster.hxx +56 -1
  192. data/ext/couchbase/couchbase/collection.hxx +111 -0
  193. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
  194. data/ext/couchbase/couchbase/conjunction_query.hxx +88 -0
  195. data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
  196. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
  197. data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
  198. data/ext/couchbase/couchbase/date_range.hxx +69 -0
  199. data/ext/couchbase/couchbase/date_range_facet.hxx +56 -0
  200. data/ext/couchbase/couchbase/date_range_facet_result.hxx +55 -0
  201. data/ext/couchbase/couchbase/date_range_query.hxx +265 -0
  202. data/ext/couchbase/couchbase/disjunction_query.hxx +109 -0
  203. data/ext/couchbase/couchbase/doc_id_query.hxx +111 -0
  204. data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
  205. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
  206. data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
  207. data/ext/couchbase/couchbase/error_codes.hxx +1 -2
  208. data/ext/couchbase/couchbase/error_context.hxx +17 -8
  209. data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
  210. data/ext/couchbase/couchbase/fmt/analytics_scan_consistency.hxx +52 -0
  211. data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
  212. data/ext/couchbase/couchbase/fmt/search_scan_consistency.hxx +49 -0
  213. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +107 -0
  214. data/ext/couchbase/couchbase/geo_distance_query.hxx +109 -0
  215. data/ext/couchbase/couchbase/geo_point.hxx +32 -0
  216. data/ext/couchbase/couchbase/geo_polygon_query.hxx +85 -0
  217. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
  218. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
  219. data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
  220. data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
  221. data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
  222. data/ext/couchbase/couchbase/get_options.hxx +2 -2
  223. data/ext/couchbase/couchbase/highlight_style.hxx +45 -0
  224. data/ext/couchbase/couchbase/insert_options.hxx +3 -3
  225. data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
  226. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  227. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
  228. data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
  229. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
  230. data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
  231. data/ext/couchbase/couchbase/management/bucket_settings.hxx +116 -0
  232. data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
  233. data/ext/couchbase/couchbase/match_all_query.hxx +43 -0
  234. data/ext/couchbase/couchbase/match_none_query.hxx +43 -0
  235. data/ext/couchbase/couchbase/match_operator.hxx +45 -0
  236. data/ext/couchbase/couchbase/match_phrase_query.hxx +108 -0
  237. data/ext/couchbase/couchbase/match_query.hxx +163 -0
  238. data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
  239. data/ext/couchbase/couchbase/numeric_range.hxx +58 -0
  240. data/ext/couchbase/couchbase/numeric_range_facet.hxx +56 -0
  241. data/ext/couchbase/couchbase/numeric_range_facet_result.hxx +55 -0
  242. data/ext/couchbase/couchbase/numeric_range_query.hxx +143 -0
  243. data/ext/couchbase/couchbase/phrase_query.hxx +93 -0
  244. data/ext/couchbase/couchbase/prefix_query.hxx +82 -0
  245. data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
  246. data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
  247. data/ext/couchbase/couchbase/query_options.hxx +18 -0
  248. data/ext/couchbase/couchbase/query_string_query.hxx +72 -0
  249. data/ext/couchbase/couchbase/regexp_query.hxx +82 -0
  250. data/ext/couchbase/couchbase/remove_options.hxx +2 -2
  251. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  252. data/ext/couchbase/couchbase/scope.hxx +40 -0
  253. data/ext/couchbase/couchbase/search_date_range.hxx +68 -0
  254. data/ext/couchbase/couchbase/search_error_context.hxx +138 -0
  255. data/ext/couchbase/couchbase/search_facet.hxx +60 -0
  256. data/ext/couchbase/couchbase/search_facet_result.hxx +50 -0
  257. data/ext/couchbase/couchbase/search_meta_data.hxx +85 -0
  258. data/ext/couchbase/couchbase/search_metrics.hxx +127 -0
  259. data/ext/couchbase/couchbase/search_numeric_range.hxx +69 -0
  260. data/ext/couchbase/couchbase/search_options.hxx +509 -0
  261. data/ext/couchbase/couchbase/search_query.hxx +69 -0
  262. data/ext/couchbase/couchbase/search_result.hxx +77 -0
  263. data/ext/couchbase/couchbase/search_row.hxx +104 -0
  264. data/ext/couchbase/couchbase/search_row_location.hxx +55 -0
  265. data/ext/couchbase/couchbase/search_row_locations.hxx +86 -0
  266. data/ext/couchbase/couchbase/search_scan_consistency.hxx +34 -0
  267. data/ext/couchbase/couchbase/search_sort.hxx +58 -0
  268. data/ext/couchbase/couchbase/search_sort_field.hxx +117 -0
  269. data/ext/couchbase/couchbase/search_sort_field_missing.hxx +26 -0
  270. data/ext/couchbase/couchbase/search_sort_field_mode.hxx +27 -0
  271. data/ext/couchbase/couchbase/search_sort_field_type.hxx +28 -0
  272. data/ext/couchbase/couchbase/search_sort_id.hxx +60 -0
  273. data/ext/couchbase/couchbase/search_sort_score.hxx +60 -0
  274. data/ext/couchbase/couchbase/search_term_range.hxx +51 -0
  275. data/ext/couchbase/couchbase/security_options.hxx +18 -0
  276. data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
  277. data/ext/couchbase/couchbase/term_facet.hxx +48 -0
  278. data/ext/couchbase/couchbase/term_facet_result.hxx +55 -0
  279. data/ext/couchbase/couchbase/term_query.hxx +151 -0
  280. data/ext/couchbase/couchbase/term_range_query.hxx +142 -0
  281. data/ext/couchbase/couchbase/touch_options.hxx +2 -2
  282. data/ext/couchbase/couchbase/tracing/request_span.hxx +63 -0
  283. data/ext/couchbase/couchbase/tracing/request_tracer.hxx +2 -40
  284. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +83 -4
  285. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +67 -0
  286. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +2 -0
  287. data/ext/couchbase/couchbase/transactions/transaction_keyspace.hxx +11 -1
  288. data/ext/couchbase/couchbase/transactions/transaction_options.hxx +79 -8
  289. data/ext/couchbase/couchbase/transactions/transaction_query_options.hxx +128 -15
  290. data/ext/couchbase/couchbase/transactions/transaction_query_result.hxx +4 -0
  291. data/ext/couchbase/couchbase/transactions/transaction_result.hxx +1 -1
  292. data/ext/couchbase/couchbase/transactions/transactions_cleanup_config.hxx +5 -3
  293. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +9 -5
  294. data/ext/couchbase/couchbase/transactions/transactions_query_config.hxx +6 -3
  295. data/ext/couchbase/couchbase/transactions.hxx +34 -1
  296. data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
  297. data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
  298. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  299. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
  300. data/ext/couchbase/couchbase/wildcard_query.hxx +83 -0
  301. data/ext/couchbase/test/CMakeLists.txt +8 -5
  302. data/ext/couchbase/test/benchmark_helper_integration.hxx +2 -2
  303. data/ext/couchbase/test/test_helper.hxx +5 -5
  304. data/ext/couchbase/test/test_integration_analytics.cxx +28 -6
  305. data/ext/couchbase/test/test_integration_collections.cxx +13 -3
  306. data/ext/couchbase/test/test_integration_connect.cxx +7 -3
  307. data/ext/couchbase/test/test_integration_crud.cxx +18 -3
  308. data/ext/couchbase/test/test_integration_diagnostics.cxx +11 -5
  309. data/ext/couchbase/test/test_integration_durability.cxx +12 -7
  310. data/ext/couchbase/test/test_integration_examples.cxx +419 -11
  311. data/ext/couchbase/test/test_integration_management.cxx +867 -368
  312. data/ext/couchbase/test/test_integration_query.cxx +87 -17
  313. data/ext/couchbase/test/test_integration_range_scan.cxx +363 -124
  314. data/ext/couchbase/test/test_integration_read_replica.cxx +48 -11
  315. data/ext/couchbase/test/test_integration_search.cxx +32 -3
  316. data/ext/couchbase/test/test_integration_subdoc.cxx +717 -11
  317. data/ext/couchbase/test/test_integration_tracer.cxx +5 -0
  318. data/ext/couchbase/test/test_integration_transcoders.cxx +13 -5
  319. data/ext/couchbase/test/{test_transaction_transaction_context.cxx → test_transaction_context.cxx} +1 -1
  320. data/ext/couchbase/test/test_transaction_examples.cxx +195 -0
  321. data/ext/couchbase/test/{test_transaction_transaction_public_async_api.cxx → test_transaction_public_async_api.cxx} +13 -12
  322. data/ext/couchbase/test/{test_transaction_transaction_public_blocking_api.cxx → test_transaction_public_blocking_api.cxx} +27 -21
  323. data/ext/couchbase/test/{test_transaction_transaction_simple.cxx → test_transaction_simple.cxx} +17 -5
  324. data/ext/couchbase/test/{test_transaction_transaction_simple_async.cxx → test_transaction_simple_async.cxx} +19 -21
  325. data/ext/couchbase/test/test_unit_config_profiles.cxx +1 -1
  326. data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
  327. data/ext/couchbase/test/test_unit_json_transcoder.cxx +4 -0
  328. data/ext/couchbase/test/test_unit_query.cxx +75 -0
  329. data/ext/couchbase/test/test_unit_search.cxx +427 -0
  330. data/ext/couchbase/test/test_unit_transaction_utils.cxx +10 -1
  331. data/ext/couchbase/test/test_unit_utils.cxx +8 -4
  332. data/ext/couchbase.cxx +641 -45
  333. data/ext/revisions.rb +3 -3
  334. data/lib/couchbase/authenticator.rb +0 -1
  335. data/lib/couchbase/cluster.rb +1 -5
  336. data/lib/couchbase/collection.rb +108 -0
  337. data/lib/couchbase/collection_options.rb +100 -0
  338. data/lib/couchbase/config_profiles.rb +1 -1
  339. data/lib/couchbase/errors.rb +5 -0
  340. data/lib/couchbase/json_transcoder.rb +12 -5
  341. data/lib/couchbase/key_value_scan.rb +125 -0
  342. data/lib/couchbase/management/collection_query_index_manager.rb +54 -15
  343. data/lib/couchbase/management/query_index_manager.rb +70 -5
  344. data/lib/couchbase/options.rb +151 -0
  345. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  346. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  347. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  348. data/lib/couchbase/scope.rb +1 -1
  349. data/lib/couchbase/search_options.rb +5 -0
  350. data/lib/couchbase/transcoder_flags.rb +62 -0
  351. data/lib/couchbase/utils/time.rb +14 -1
  352. data/lib/couchbase/version.rb +1 -1
  353. metadata +175 -13
  354. data/ext/couchbase/core/config_profile.cxx +0 -47
  355. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
data/ext/couchbase.cxx CHANGED
@@ -33,9 +33,12 @@
33
33
  #include <core/platform/terminate_handler.h>
34
34
 
35
35
  #include <core/cluster.hxx>
36
+
37
+ #include <core/agent_group.hxx>
36
38
  #include <core/design_document_namespace_fmt.hxx>
37
39
  #include <core/logger/configuration.hxx>
38
40
  #include <core/operations.hxx>
41
+
39
42
  #include <core/operations/management/analytics.hxx>
40
43
  #include <core/operations/management/bucket.hxx>
41
44
  #include <core/operations/management/cluster_developer_preview_enable.hxx>
@@ -45,6 +48,12 @@
45
48
  #include <core/operations/management/user.hxx>
46
49
  #include <core/operations/management/view.hxx>
47
50
 
51
+ #include <core/impl/subdoc/path_flags.hxx>
52
+
53
+ #include <core/range_scan_options.hxx>
54
+ #include <core/range_scan_orchestrator.hxx>
55
+ #include <core/range_scan_orchestrator_options.hxx>
56
+
48
57
  #include <core/io/dns_client.hxx>
49
58
  #include <core/io/dns_config.hxx>
50
59
  #include <core/utils/connection_string.hxx>
@@ -270,9 +279,9 @@ init_versions(VALUE mCouchbase)
270
279
  VALUE cb_CoreInfo = rb_hash_new();
271
280
  for (const auto& [name, value] : couchbase::core::meta::sdk_build_info()) {
272
281
  if (name == "version_major" || name == "version_minor" || name == "version_patch" || name == "version_build" ||
273
- name == "__cplusplus" || name == "_MSC_VER") {
282
+ name == "__cplusplus" || name == "_MSC_VER" || name == "mozilla_ca_bundle_size") {
274
283
  rb_hash_aset(cb_CoreInfo, rb_id2sym(rb_intern(name.c_str())), INT2FIX(std::stoi(value)));
275
- } else if (name == "snapshot" || name == "static_stdlib" || name == "static_openssl") {
284
+ } else if (name == "snapshot" || name == "static_stdlib" || name == "static_openssl" || name == "mozilla_ca_bundle_embedded") {
276
285
  rb_hash_aset(cb_CoreInfo, rb_id2sym(rb_intern(name.c_str())), value == "true" ? Qtrue : Qfalse);
277
286
  } else {
278
287
  rb_hash_aset(cb_CoreInfo, rb_id2sym(rb_intern(name.c_str())), rb_str_freeze(rb_str_new_cstr(value.c_str())));
@@ -435,7 +444,7 @@ cb_backend_close(cb_backend_data* backend)
435
444
  static void
436
445
  cb_Backend_mark(void* /* ptr */)
437
446
  {
438
- /* no embeded ruby objects -- no mark */
447
+ /* no embedded ruby objects -- no mark */
439
448
  }
440
449
 
441
450
  static void
@@ -495,6 +504,8 @@ cb_backend_to_cluster(VALUE self)
495
504
  return backend->cluster;
496
505
  }
497
506
 
507
+ static VALUE eCouchbaseError;
508
+
498
509
  static VALUE eAmbiguousTimeout;
499
510
  static VALUE eAuthenticationFailure;
500
511
  static VALUE eBucketExists;
@@ -534,6 +545,7 @@ static VALUE eInvalidArgument;
534
545
  static VALUE eJobQueueFull;
535
546
  static VALUE eLinkNotFound;
536
547
  static VALUE eLinkExists;
548
+ static VALUE eMutationTokenOutdated;
537
549
  static VALUE eNumberTooBig;
538
550
  static VALUE eParsingFailure;
539
551
  static VALUE ePathExists;
@@ -586,7 +598,7 @@ static void
586
598
  init_exceptions(VALUE mCouchbase)
587
599
  {
588
600
  VALUE mError = rb_define_module_under(mCouchbase, "Error");
589
- VALUE eCouchbaseError = rb_define_class_under(mError, "CouchbaseError", rb_eStandardError);
601
+ eCouchbaseError = rb_define_class_under(mError, "CouchbaseError", rb_eStandardError);
590
602
 
591
603
  VALUE eTimeout = rb_define_class_under(mError, "Timeout", eCouchbaseError);
592
604
 
@@ -629,6 +641,7 @@ init_exceptions(VALUE mCouchbase)
629
641
  eJobQueueFull = rb_define_class_under(mError, "JobQueueFull", eCouchbaseError);
630
642
  eLinkNotFound = rb_define_class_under(mError, "LinkNotFound", eCouchbaseError);
631
643
  eLinkExists = rb_define_class_under(mError, "LinkExists", eCouchbaseError);
644
+ eMutationTokenOutdated = rb_define_class_under(mError, "MutationTokenOutdated", eCouchbaseError);
632
645
  eNumberTooBig = rb_define_class_under(mError, "NumberTooBig", eCouchbaseError);
633
646
  eParsingFailure = rb_define_class_under(mError, "ParsingFailure", eCouchbaseError);
634
647
  ePathExists = rb_define_class_under(mError, "PathExists", eCouchbaseError);
@@ -784,6 +797,9 @@ cb_map_error_code(std::error_code ec, const std::string& message, bool include_e
784
797
  case couchbase::errc::key_value::durable_write_re_commit_in_progress:
785
798
  return rb_exc_new_cstr(eDurableWriteReCommitInProgress, what.c_str());
786
799
 
800
+ case couchbase::errc::key_value::mutation_token_outdated:
801
+ return rb_exc_new_cstr(eMutationTokenOutdated, what.c_str());
802
+
787
803
  case couchbase::errc::key_value::path_not_found:
788
804
  return rb_exc_new_cstr(ePathNotFound, what.c_str());
789
805
 
@@ -834,6 +850,10 @@ cb_map_error_code(std::error_code ec, const std::string& message, bool include_e
834
850
 
835
851
  case couchbase::errc::key_value::cannot_revive_living_document:
836
852
  return rb_exc_new_cstr(eCannotReviveLivingDocument, what.c_str());
853
+
854
+ case couchbase::errc::key_value::range_scan_completed:
855
+ // Should not be exposed to the Ruby SDK, map it to a BackendError
856
+ return rb_exc_new_cstr(eBackendError, what.c_str());
837
857
  }
838
858
  } else if (ec.category() == couchbase::core::impl::query_category()) {
839
859
  switch (static_cast<couchbase::errc::query>(ec.value())) {
@@ -1253,9 +1273,7 @@ cb_map_error_code(const couchbase::core::error_context::search& ctx, const std::
1253
1273
  rb_hash_aset(error_context, rb_id2sym(rb_intern("error")), cb_str_new(error));
1254
1274
  rb_hash_aset(error_context, rb_id2sym(rb_intern("client_context_id")), cb_str_new(ctx.client_context_id));
1255
1275
  rb_hash_aset(error_context, rb_id2sym(rb_intern("index_name")), cb_str_new(ctx.index_name));
1256
- if (ctx.query) {
1257
- rb_hash_aset(error_context, rb_id2sym(rb_intern("query")), cb_str_new(ctx.query.value()));
1258
- }
1276
+ rb_hash_aset(error_context, rb_id2sym(rb_intern("query")), cb_str_new(ctx.query));
1259
1277
  if (ctx.parameters) {
1260
1278
  rb_hash_aset(error_context, rb_id2sym(rb_intern("parameters")), cb_str_new(ctx.parameters.value()));
1261
1279
  }
@@ -1592,7 +1610,7 @@ extract_durability_level(VALUE options)
1592
1610
  if (VALUE val = rb_hash_aref(options, property_name); !NIL_P(val)) {
1593
1611
  ID level = rb_sym2id(val);
1594
1612
  if (level == rb_intern("none")) {
1595
- return couchbase::durability_level::none;
1613
+ return {};
1596
1614
  }
1597
1615
  if (level == rb_intern("majority")) {
1598
1616
  return couchbase::durability_level::majority;
@@ -1615,7 +1633,7 @@ extract_legacy_durability_persist_to(VALUE options)
1615
1633
  if (VALUE val = rb_hash_aref(options, property_name); !NIL_P(val)) {
1616
1634
  ID mode = rb_sym2id(val);
1617
1635
  if (mode == rb_intern("none")) {
1618
- return couchbase::persist_to::none;
1636
+ return {};
1619
1637
  }
1620
1638
  if (mode == rb_intern("active")) {
1621
1639
  return couchbase::persist_to::active;
@@ -1644,7 +1662,7 @@ extract_legacy_durability_replicate_to(VALUE options)
1644
1662
  if (VALUE val = rb_hash_aref(options, property_name); !NIL_P(val)) {
1645
1663
  ID mode = rb_sym2id(val);
1646
1664
  if (mode == rb_intern("none")) {
1647
- return couchbase::replicate_to::none;
1665
+ return {};
1648
1666
  }
1649
1667
  if (mode == rb_intern("one")) {
1650
1668
  return couchbase::replicate_to::one;
@@ -1799,8 +1817,9 @@ cb_extract_cas(couchbase::cas& field, VALUE cas)
1799
1817
  }
1800
1818
  }
1801
1819
 
1820
+ template<typename Boolean>
1802
1821
  static void
1803
- cb_extract_option_bool(bool& field, VALUE options, const char* name)
1822
+ cb_extract_option_bool(Boolean& field, VALUE options, const char* name)
1804
1823
  {
1805
1824
  if (!NIL_P(options) && TYPE(options) == T_HASH) {
1806
1825
  VALUE val = rb_hash_aref(options, rb_id2sym(rb_intern(name)));
@@ -3410,7 +3429,7 @@ cb_Backend_document_decrement(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3410
3429
  static VALUE
3411
3430
  cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
3412
3431
  {
3413
- const auto& core = cb_backend_to_cluster(self);
3432
+ const auto& cluster = cb_backend_to_cluster(self);
3414
3433
 
3415
3434
  Check_Type(bucket, T_STRING);
3416
3435
  Check_Type(scope, T_STRING);
@@ -3426,10 +3445,6 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3426
3445
  }
3427
3446
 
3428
3447
  try {
3429
- couchbase::lookup_in_options opts;
3430
- couchbase::ruby::set_timeout(opts, options);
3431
- couchbase::ruby::set_access_deleted(opts, options);
3432
-
3433
3448
  couchbase::core::document_id doc_id{
3434
3449
  cb_string_new(bucket),
3435
3450
  cb_string_new(scope),
@@ -3437,12 +3452,15 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3437
3452
  cb_string_new(id),
3438
3453
  };
3439
3454
 
3455
+ couchbase::core::operations::lookup_in_request req{ doc_id };
3456
+ cb_extract_timeout(req, options);
3457
+ cb_extract_option_bool(req.access_deleted, options, "access_deleted");
3458
+
3440
3459
  static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
3441
3460
  static VALUE path_property = rb_id2sym(rb_intern("path"));
3442
3461
  static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
3443
3462
 
3444
3463
  auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
3445
- couchbase::lookup_in_specs cxx_specs;
3446
3464
  for (std::size_t i = 0; i < entries_size; ++i) {
3447
3465
  VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
3448
3466
  cb_check_type(entry, T_HASH);
@@ -3451,29 +3469,138 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3451
3469
  bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
3452
3470
  VALUE path = rb_hash_aref(entry, path_property);
3453
3471
  cb_check_type(path, T_STRING);
3472
+ auto opcode = couchbase::core::impl::subdoc::opcode{};
3454
3473
  if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
3455
- cxx_specs.push_back(couchbase::lookup_in_specs::get("").xattr(xattr));
3474
+ opcode = couchbase::core::impl::subdoc::opcode::get_doc;
3456
3475
  } else if (operation_id == rb_intern("get")) {
3457
- cxx_specs.push_back(couchbase::lookup_in_specs::get(cb_string_new(path)).xattr(xattr));
3476
+ opcode = couchbase::core::impl::subdoc::opcode::get;
3458
3477
  } else if (operation_id == rb_intern("exists")) {
3459
- cxx_specs.push_back(couchbase::lookup_in_specs::exists(cb_string_new(path)).xattr(xattr));
3478
+ opcode = couchbase::core::impl::subdoc::opcode::exists;
3460
3479
  } else if (operation_id == rb_intern("count")) {
3461
- cxx_specs.push_back(couchbase::lookup_in_specs::count(cb_string_new(path)).xattr(xattr));
3480
+ opcode = couchbase::core::impl::subdoc::opcode::get_count;
3462
3481
  } else {
3463
3482
  throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
3464
3483
  }
3465
3484
  cb_check_type(path, T_STRING);
3485
+
3486
+ req.specs.emplace_back(couchbase::core::impl::subdoc::command{
3487
+ opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
3466
3488
  }
3467
3489
 
3468
- auto f = couchbase::cluster(core)
3469
- .bucket(cb_string_new(bucket))
3470
- .scope(cb_string_new(scope))
3471
- .collection(cb_string_new(collection))
3472
- .lookup_in(cb_string_new(id), cxx_specs, opts);
3490
+ auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_response>>();
3491
+ auto f = barrier->get_future();
3492
+ cluster->execute(req, [barrier](couchbase::core::operations::lookup_in_response&& resp) { barrier->set_value(std::move(resp)); });
3493
+ auto resp = cb_wait_for_future(f);
3494
+ if (resp.ctx.ec()) {
3495
+ cb_throw_error_code(resp.ctx, "unable to perform lookup_in operation");
3496
+ }
3473
3497
 
3474
- auto [ctx, resp] = cb_wait_for_future(f);
3475
- if (ctx.ec()) {
3476
- cb_throw_error_code(ctx, "unable to lookup_in");
3498
+ static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
3499
+ static VALUE fields_property = rb_id2sym(rb_intern("fields"));
3500
+ static VALUE index_property = rb_id2sym(rb_intern("index"));
3501
+ static VALUE exists_property = rb_id2sym(rb_intern("exists"));
3502
+ static VALUE cas_property = rb_id2sym(rb_intern("cas"));
3503
+ static VALUE value_property = rb_id2sym(rb_intern("value"));
3504
+ static VALUE error_property = rb_id2sym(rb_intern("error"));
3505
+
3506
+ VALUE res = rb_hash_new();
3507
+ rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas));
3508
+ VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
3509
+ rb_hash_aset(res, fields_property, fields);
3510
+ rb_hash_aset(res, deleted_property, resp.deleted ? Qtrue : Qfalse);
3511
+ for (std::size_t i = 0; i < entries_size; ++i) {
3512
+ auto resp_entry = resp.fields.at(i);
3513
+ VALUE entry = rb_hash_new();
3514
+ rb_hash_aset(entry, index_property, ULL2NUM(resp_entry.original_index));
3515
+ rb_hash_aset(entry, exists_property, resp_entry.exists ? Qtrue : Qfalse);
3516
+ rb_hash_aset(entry, path_property, cb_str_new(resp_entry.path));
3517
+ if (!resp_entry.value.empty()) {
3518
+ rb_hash_aset(entry, value_property, cb_str_new(resp_entry.value));
3519
+ }
3520
+ if (resp_entry.ec && resp_entry.ec != couchbase::errc::key_value::path_not_found) {
3521
+ rb_hash_aset(entry,
3522
+ error_property,
3523
+ cb_map_error_code(resp_entry.ec,
3524
+ fmt::format("error getting result for spec at index {}, path \"{}\"", i, resp_entry.path)));
3525
+ }
3526
+ rb_ary_store(fields, static_cast<long>(i), entry);
3527
+ }
3528
+ return res;
3529
+ } catch (const std::system_error& se) {
3530
+ rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
3531
+ } catch (const ruby_exception& e) {
3532
+ rb_exc_raise(e.exception_object());
3533
+ }
3534
+ return Qnil;
3535
+ }
3536
+
3537
+ static VALUE
3538
+ cb_Backend_document_lookup_in_any_replica(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
3539
+ {
3540
+ const auto& cluster = cb_backend_to_cluster(self);
3541
+
3542
+ Check_Type(bucket, T_STRING);
3543
+ Check_Type(scope, T_STRING);
3544
+ Check_Type(collection, T_STRING);
3545
+ Check_Type(id, T_STRING);
3546
+ Check_Type(specs, T_ARRAY);
3547
+ if (RARRAY_LEN(specs) <= 0) {
3548
+ rb_raise(rb_eArgError, "Array with specs cannot be empty");
3549
+ return Qnil;
3550
+ }
3551
+ if (!NIL_P(options)) {
3552
+ Check_Type(options, T_HASH);
3553
+ }
3554
+
3555
+ try {
3556
+ couchbase::core::document_id doc_id{
3557
+ cb_string_new(bucket),
3558
+ cb_string_new(scope),
3559
+ cb_string_new(collection),
3560
+ cb_string_new(id),
3561
+ };
3562
+
3563
+ couchbase::core::operations::lookup_in_any_replica_request req{ doc_id };
3564
+ cb_extract_timeout(req, options);
3565
+
3566
+ static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
3567
+ static VALUE path_property = rb_id2sym(rb_intern("path"));
3568
+ static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
3569
+
3570
+ auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
3571
+ for (std::size_t i = 0; i < entries_size; ++i) {
3572
+ VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
3573
+ cb_check_type(entry, T_HASH);
3574
+ VALUE operation = rb_hash_aref(entry, opcode_property);
3575
+ cb_check_type(operation, T_SYMBOL);
3576
+ bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
3577
+ VALUE path = rb_hash_aref(entry, path_property);
3578
+ cb_check_type(path, T_STRING);
3579
+ auto opcode = couchbase::core::impl::subdoc::opcode{};
3580
+ if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
3581
+ opcode = couchbase::core::impl::subdoc::opcode::get_doc;
3582
+ } else if (operation_id == rb_intern("get")) {
3583
+ opcode = couchbase::core::impl::subdoc::opcode::get;
3584
+ } else if (operation_id == rb_intern("exists")) {
3585
+ opcode = couchbase::core::impl::subdoc::opcode::exists;
3586
+ } else if (operation_id == rb_intern("count")) {
3587
+ opcode = couchbase::core::impl::subdoc::opcode::get_count;
3588
+ } else {
3589
+ throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
3590
+ }
3591
+ cb_check_type(path, T_STRING);
3592
+
3593
+ req.specs.emplace_back(couchbase::core::impl::subdoc::command{
3594
+ opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
3595
+ }
3596
+
3597
+ auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_any_replica_response>>();
3598
+ auto f = barrier->get_future();
3599
+ cluster->execute(
3600
+ req, [barrier](couchbase::core::operations::lookup_in_any_replica_response&& resp) { barrier->set_value(std::move(resp)); });
3601
+ auto resp = cb_wait_for_future(f);
3602
+ if (resp.ctx.ec()) {
3603
+ cb_throw_error_code(resp.ctx, "unable to perform lookup_in_any_replica operation");
3477
3604
  }
3478
3605
 
3479
3606
  static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
@@ -3482,23 +3609,153 @@ cb_Backend_document_lookup_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3482
3609
  static VALUE exists_property = rb_id2sym(rb_intern("exists"));
3483
3610
  static VALUE cas_property = rb_id2sym(rb_intern("cas"));
3484
3611
  static VALUE value_property = rb_id2sym(rb_intern("value"));
3612
+ static VALUE error_property = rb_id2sym(rb_intern("error"));
3613
+ static VALUE is_replica_property = rb_id2sym(rb_intern("is_replica"));
3485
3614
 
3486
3615
  VALUE res = rb_hash_new();
3487
- rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas()));
3616
+ rb_hash_aset(res, cas_property, cb_cas_to_num(resp.cas));
3488
3617
  VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
3489
3618
  rb_hash_aset(res, fields_property, fields);
3490
- rb_hash_aset(res, deleted_property, resp.is_deleted() ? Qtrue : Qfalse);
3619
+ rb_hash_aset(res, deleted_property, resp.deleted ? Qtrue : Qfalse);
3620
+ rb_hash_aset(res, is_replica_property, resp.is_replica ? Qtrue : Qfalse);
3621
+
3491
3622
  for (std::size_t i = 0; i < entries_size; ++i) {
3623
+ auto resp_entry = resp.fields.at(i);
3492
3624
  VALUE entry = rb_hash_new();
3493
- rb_hash_aset(entry, index_property, ULL2NUM(i));
3494
- rb_hash_aset(entry, exists_property, resp.exists(i) ? Qtrue : Qfalse);
3495
- rb_hash_aset(entry, path_property, rb_hash_aref(rb_ary_entry(specs, static_cast<long>(i)), path_property));
3496
- if (resp.has_value(i)) {
3497
- auto value = resp.content_as<tao::json::value>(i);
3498
- rb_hash_aset(entry, value_property, cb_str_new(couchbase::core::utils::json::generate(value)));
3625
+ rb_hash_aset(entry, index_property, ULL2NUM(resp_entry.original_index));
3626
+ rb_hash_aset(entry, exists_property, resp_entry.exists ? Qtrue : Qfalse);
3627
+ rb_hash_aset(entry, path_property, cb_str_new(resp_entry.path));
3628
+ if (!resp_entry.value.empty()) {
3629
+ rb_hash_aset(entry, value_property, cb_str_new(resp_entry.value));
3630
+ }
3631
+ if (resp_entry.ec && resp_entry.ec != couchbase::errc::key_value::path_not_found) {
3632
+ rb_hash_aset(entry,
3633
+ error_property,
3634
+ cb_map_error_code(resp_entry.ec,
3635
+ fmt::format("error getting result for spec at index {}, path \"{}\"", i, resp_entry.path)));
3499
3636
  }
3500
3637
  rb_ary_store(fields, static_cast<long>(i), entry);
3501
3638
  }
3639
+
3640
+ return res;
3641
+ } catch (const std::system_error& se) {
3642
+ rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
3643
+ } catch (const ruby_exception& e) {
3644
+ rb_exc_raise(e.exception_object());
3645
+ }
3646
+ return Qnil;
3647
+ }
3648
+
3649
+ static VALUE
3650
+ cb_Backend_document_lookup_in_all_replicas(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE id, VALUE specs, VALUE options)
3651
+ {
3652
+ const auto& cluster = cb_backend_to_cluster(self);
3653
+
3654
+ Check_Type(bucket, T_STRING);
3655
+ Check_Type(scope, T_STRING);
3656
+ Check_Type(collection, T_STRING);
3657
+ Check_Type(id, T_STRING);
3658
+ Check_Type(specs, T_ARRAY);
3659
+ if (RARRAY_LEN(specs) <= 0) {
3660
+ rb_raise(rb_eArgError, "Array with specs cannot be empty");
3661
+ return Qnil;
3662
+ }
3663
+ if (!NIL_P(options)) {
3664
+ Check_Type(options, T_HASH);
3665
+ }
3666
+
3667
+ try {
3668
+ couchbase::core::document_id doc_id{
3669
+ cb_string_new(bucket),
3670
+ cb_string_new(scope),
3671
+ cb_string_new(collection),
3672
+ cb_string_new(id),
3673
+ };
3674
+
3675
+ couchbase::core::operations::lookup_in_all_replicas_request req{ doc_id };
3676
+ cb_extract_timeout(req, options);
3677
+
3678
+ static VALUE xattr_property = rb_id2sym(rb_intern("xattr"));
3679
+ static VALUE path_property = rb_id2sym(rb_intern("path"));
3680
+ static VALUE opcode_property = rb_id2sym(rb_intern("opcode"));
3681
+
3682
+ auto entries_size = static_cast<std::size_t>(RARRAY_LEN(specs));
3683
+ for (std::size_t i = 0; i < entries_size; ++i) {
3684
+ VALUE entry = rb_ary_entry(specs, static_cast<long>(i));
3685
+ cb_check_type(entry, T_HASH);
3686
+ VALUE operation = rb_hash_aref(entry, opcode_property);
3687
+ cb_check_type(operation, T_SYMBOL);
3688
+ bool xattr = RTEST(rb_hash_aref(entry, xattr_property));
3689
+ VALUE path = rb_hash_aref(entry, path_property);
3690
+ cb_check_type(path, T_STRING);
3691
+ auto opcode = couchbase::core::impl::subdoc::opcode{};
3692
+ if (ID operation_id = rb_sym2id(operation); operation_id == rb_intern("get_doc")) {
3693
+ opcode = couchbase::core::impl::subdoc::opcode::get_doc;
3694
+ } else if (operation_id == rb_intern("get")) {
3695
+ opcode = couchbase::core::impl::subdoc::opcode::get;
3696
+ } else if (operation_id == rb_intern("exists")) {
3697
+ opcode = couchbase::core::impl::subdoc::opcode::exists;
3698
+ } else if (operation_id == rb_intern("count")) {
3699
+ opcode = couchbase::core::impl::subdoc::opcode::get_count;
3700
+ } else {
3701
+ throw ruby_exception(eInvalidArgument, rb_sprintf("unsupported operation for subdocument lookup: %+" PRIsVALUE, operation));
3702
+ }
3703
+ cb_check_type(path, T_STRING);
3704
+
3705
+ req.specs.emplace_back(couchbase::core::impl::subdoc::command{
3706
+ opcode, cb_string_new(path), {}, couchbase::core::impl::subdoc::build_lookup_in_path_flags(xattr) });
3707
+ }
3708
+
3709
+ auto barrier = std::make_shared<std::promise<couchbase::core::operations::lookup_in_all_replicas_response>>();
3710
+ auto f = barrier->get_future();
3711
+ cluster->execute(
3712
+ req, [barrier](couchbase::core::operations::lookup_in_all_replicas_response&& resp) { barrier->set_value(std::move(resp)); });
3713
+ auto resp = cb_wait_for_future(f);
3714
+ if (resp.ctx.ec()) {
3715
+ cb_throw_error_code(resp.ctx, "unable to perform lookup_in_all_replicas operation");
3716
+ }
3717
+
3718
+ static VALUE deleted_property = rb_id2sym(rb_intern("deleted"));
3719
+ static VALUE fields_property = rb_id2sym(rb_intern("fields"));
3720
+ static VALUE index_property = rb_id2sym(rb_intern("index"));
3721
+ static VALUE exists_property = rb_id2sym(rb_intern("exists"));
3722
+ static VALUE cas_property = rb_id2sym(rb_intern("cas"));
3723
+ static VALUE value_property = rb_id2sym(rb_intern("value"));
3724
+ static VALUE error_property = rb_id2sym(rb_intern("error"));
3725
+ static VALUE is_replica_property = rb_id2sym(rb_intern("is_replica"));
3726
+
3727
+ auto lookup_in_entries_size = resp.entries.size();
3728
+ VALUE res = rb_ary_new_capa(static_cast<long>(lookup_in_entries_size));
3729
+ for (std::size_t j = 0; j < lookup_in_entries_size; ++j) {
3730
+ auto lookup_in_entry = resp.entries.at(j);
3731
+ VALUE lookup_in_entry_res = rb_hash_new();
3732
+ rb_hash_aset(lookup_in_entry_res, cas_property, cb_cas_to_num(lookup_in_entry.cas));
3733
+ VALUE fields = rb_ary_new_capa(static_cast<long>(entries_size));
3734
+ rb_hash_aset(lookup_in_entry_res, fields_property, fields);
3735
+ rb_hash_aset(lookup_in_entry_res, deleted_property, lookup_in_entry.deleted ? Qtrue : Qfalse);
3736
+ rb_hash_aset(lookup_in_entry_res, is_replica_property, lookup_in_entry.is_replica ? Qtrue : Qfalse);
3737
+
3738
+ for (std::size_t i = 0; i < entries_size; ++i) {
3739
+ auto field_entry = lookup_in_entry.fields.at(i);
3740
+ VALUE entry = rb_hash_new();
3741
+ rb_hash_aset(entry, index_property, ULL2NUM(field_entry.original_index));
3742
+ rb_hash_aset(entry, exists_property, field_entry.exists ? Qtrue : Qfalse);
3743
+ rb_hash_aset(entry, path_property, cb_str_new(field_entry.path));
3744
+ if (!field_entry.value.empty()) {
3745
+ rb_hash_aset(entry, value_property, cb_str_new(field_entry.value));
3746
+ }
3747
+ if (field_entry.ec && field_entry.ec != couchbase::errc::key_value::path_not_found) {
3748
+ rb_hash_aset(
3749
+ entry,
3750
+ error_property,
3751
+ cb_map_error_code(field_entry.ec,
3752
+ fmt::format("error getting result for spec at index {}, path \"{}\"", i, field_entry.path)));
3753
+ }
3754
+ rb_ary_store(fields, static_cast<long>(i), entry);
3755
+ }
3756
+ rb_ary_store(res, static_cast<long>(j), lookup_in_entry_res);
3757
+ }
3758
+
3502
3759
  return res;
3503
3760
  } catch (const std::system_error& se) {
3504
3761
  rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
@@ -3662,6 +3919,284 @@ cb_Backend_document_mutate_in(VALUE self, VALUE bucket, VALUE scope, VALUE colle
3662
3919
  return Qnil;
3663
3920
  }
3664
3921
 
3922
+ struct cb_core_scan_result_data {
3923
+ std::unique_ptr<couchbase::core::scan_result> scan_result{};
3924
+ };
3925
+
3926
+ static void
3927
+ cb_CoreScanResult_mark(void* ptr)
3928
+ {
3929
+ /* No embedded Ruby objects */
3930
+ }
3931
+
3932
+ static void
3933
+ cb_CoreScanResult_free(void* ptr)
3934
+ {
3935
+ auto* data = static_cast<cb_core_scan_result_data*>(ptr);
3936
+ if (data->scan_result != nullptr && !data->scan_result->is_cancelled()) {
3937
+ data->scan_result->cancel();
3938
+ }
3939
+ data->scan_result.reset();
3940
+ ruby_xfree(data);
3941
+ }
3942
+
3943
+ static const rb_data_type_t cb_core_scan_result_type {
3944
+ .wrap_struct_name = "Couchbase/Backend/CoreScanResult",
3945
+ .function = {
3946
+ .dmark = cb_CoreScanResult_mark,
3947
+ .dfree = cb_CoreScanResult_free,
3948
+ },
3949
+ .data = nullptr,
3950
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
3951
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
3952
+ #endif
3953
+ };
3954
+
3955
+ static VALUE
3956
+ cb_CoreScanResult_allocate(VALUE klass)
3957
+ {
3958
+ cb_core_scan_result_data* data = nullptr;
3959
+ VALUE obj = TypedData_Make_Struct(klass, cb_core_scan_result_data, &cb_core_scan_result_type, data);
3960
+ return obj;
3961
+ }
3962
+
3963
+ static VALUE
3964
+ cb_CoreScanResult_is_cancelled(VALUE self)
3965
+ {
3966
+ cb_core_scan_result_data* data = nullptr;
3967
+ TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
3968
+ auto resp = data->scan_result->is_cancelled();
3969
+ if (resp) {
3970
+ return Qtrue;
3971
+ } else {
3972
+ return Qfalse;
3973
+ }
3974
+ }
3975
+
3976
+ static VALUE
3977
+ cb_CoreScanResult_cancel(VALUE self)
3978
+ {
3979
+ cb_core_scan_result_data* data = nullptr;
3980
+ TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
3981
+ data->scan_result->cancel();
3982
+ return Qnil;
3983
+ }
3984
+
3985
+ static VALUE
3986
+ cb_CoreScanResult_next_item(VALUE self)
3987
+ {
3988
+ try {
3989
+ cb_core_scan_result_data* data = nullptr;
3990
+ TypedData_Get_Struct(self, cb_core_scan_result_data, &cb_core_scan_result_type, data);
3991
+ auto barrier = std::make_shared<std::promise<tl::expected<couchbase::core::range_scan_item, std::error_code>>>();
3992
+ auto f = barrier->get_future();
3993
+ data->scan_result->next([barrier](couchbase::core::range_scan_item item, std::error_code ec) {
3994
+ if (ec) {
3995
+ return barrier->set_value(tl::unexpected(ec));
3996
+ } else {
3997
+ return barrier->set_value(item);
3998
+ }
3999
+ });
4000
+ auto resp = cb_wait_for_future(f);
4001
+ if (!resp.has_value()) {
4002
+ // If the error code is range_scan_completed return nil without raising an exception (nil signifies that there
4003
+ // are no more items)
4004
+ if (resp.error() != couchbase::errc::key_value::range_scan_completed) {
4005
+ cb_throw_error_code(resp.error(), "unable to fetch next scan item");
4006
+ }
4007
+ // Release ownership of scan_result unique pointer
4008
+ return Qnil;
4009
+ }
4010
+ auto item = resp.value();
4011
+ VALUE res = rb_hash_new();
4012
+ rb_hash_aset(res, rb_id2sym(rb_intern("id")), cb_str_new(item.key));
4013
+ if (item.body.has_value()) {
4014
+ auto body = item.body.value();
4015
+ rb_hash_aset(res, rb_id2sym(rb_intern("id")), cb_str_new(item.key));
4016
+ rb_hash_aset(res, rb_id2sym(rb_intern("encoded")), cb_str_new(body.value));
4017
+ rb_hash_aset(res, rb_id2sym(rb_intern("cas")), cb_cas_to_num(body.cas));
4018
+ rb_hash_aset(res, rb_id2sym(rb_intern("flags")), UINT2NUM(body.flags));
4019
+ rb_hash_aset(res, rb_id2sym(rb_intern("expiry")), UINT2NUM(body.expiry));
4020
+ rb_hash_aset(res, rb_id2sym(rb_intern("id_only")), Qfalse);
4021
+ } else {
4022
+ rb_hash_aset(res, rb_id2sym(rb_intern("id_only")), Qtrue);
4023
+ }
4024
+ return res;
4025
+ } catch (const std::system_error& se) {
4026
+ rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
4027
+ } catch (const ruby_exception& e) {
4028
+ rb_exc_raise(e.exception_object());
4029
+ }
4030
+ return Qnil;
4031
+ }
4032
+
4033
+ static VALUE
4034
+ cb_Backend_document_scan_create(VALUE self, VALUE bucket, VALUE scope, VALUE collection, VALUE scan_type, VALUE options)
4035
+ {
4036
+ const auto& cluster = cb_backend_to_cluster(self);
4037
+
4038
+ Check_Type(bucket, T_STRING);
4039
+ Check_Type(scope, T_STRING);
4040
+ Check_Type(collection, T_STRING);
4041
+ Check_Type(scan_type, T_HASH);
4042
+ if (!NIL_P(options)) {
4043
+ Check_Type(options, T_HASH);
4044
+ }
4045
+
4046
+ try {
4047
+ couchbase::core::range_scan_orchestrator_options orchestrator_options{};
4048
+ cb_extract_timeout(orchestrator_options, options);
4049
+ cb_extract_option_bool(orchestrator_options.ids_only, options, "ids_only");
4050
+ cb_extract_option_number(orchestrator_options.batch_item_limit, options, "batch_item_limit");
4051
+ cb_extract_option_number(orchestrator_options.batch_byte_limit, options, "batch_byte_limit");
4052
+ cb_extract_option_number(orchestrator_options.concurrency, options, "concurrency");
4053
+
4054
+ // Extracting the mutation state
4055
+ if (VALUE mutation_state = rb_hash_aref(options, rb_id2sym(rb_intern("mutation_state"))); !NIL_P(mutation_state)) {
4056
+ cb_check_type(mutation_state, T_ARRAY);
4057
+ auto state_size = static_cast<std::size_t>(RARRAY_LEN(mutation_state));
4058
+
4059
+ if (state_size > 0) {
4060
+ auto core_mut_state = couchbase::core::mutation_state{};
4061
+ core_mut_state.tokens.reserve(state_size);
4062
+ for (std::size_t i = 0; i < state_size; ++i) {
4063
+ VALUE token = rb_ary_entry(mutation_state, static_cast<long>(i));
4064
+ cb_check_type(token, T_HASH);
4065
+ VALUE bucket_name = rb_hash_aref(token, rb_id2sym(rb_intern("bucket_name")));
4066
+ cb_check_type(bucket_name, T_STRING);
4067
+ VALUE partition_id = rb_hash_aref(token, rb_id2sym(rb_intern("partition_id")));
4068
+ cb_check_type(partition_id, T_FIXNUM);
4069
+ VALUE partition_uuid = rb_hash_aref(token, rb_id2sym(rb_intern("partition_uuid")));
4070
+ switch (TYPE(partition_uuid)) {
4071
+ case T_FIXNUM:
4072
+ case T_BIGNUM:
4073
+ break;
4074
+ default:
4075
+ rb_raise(rb_eArgError, "partition_uuid must be an Integer");
4076
+ }
4077
+ VALUE sequence_number = rb_hash_aref(token, rb_id2sym(rb_intern("sequence_number")));
4078
+ switch (TYPE(sequence_number)) {
4079
+ case T_FIXNUM:
4080
+ case T_BIGNUM:
4081
+ break;
4082
+ default:
4083
+ rb_raise(rb_eArgError, "sequence_number must be an Integer");
4084
+ }
4085
+ core_mut_state.tokens.emplace_back(NUM2ULL(partition_uuid),
4086
+ NUM2ULL(sequence_number),
4087
+ gsl::narrow_cast<std::uint16_t>(NUM2UINT(partition_id)),
4088
+ cb_string_new(bucket_name));
4089
+ }
4090
+
4091
+ orchestrator_options.consistent_with = core_mut_state;
4092
+ }
4093
+ }
4094
+
4095
+ auto bucket_name = cb_string_new(bucket);
4096
+ auto scope_name = cb_string_new(scope);
4097
+ auto collection_name = cb_string_new(collection);
4098
+
4099
+ // Getting the operation agent
4100
+ auto agent_group = couchbase::core::agent_group(cluster->io_context(), couchbase::core::agent_group_config{ { cluster } });
4101
+ agent_group.open_bucket(bucket_name);
4102
+ auto agent = agent_group.get_agent(bucket_name);
4103
+ if (!agent.has_value()) {
4104
+ rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get operation agent");
4105
+ return Qnil;
4106
+ }
4107
+
4108
+ // Getting the vbucket map
4109
+ auto barrier = std::make_shared<std::promise<tl::expected<couchbase::core::topology::configuration, std::error_code>>>();
4110
+ auto f = barrier->get_future();
4111
+ cluster->with_bucket_configuration(bucket_name,
4112
+ [barrier](std::error_code ec, const couchbase::core::topology::configuration& config) mutable {
4113
+ if (ec) {
4114
+ return barrier->set_value(tl::unexpected(ec));
4115
+ }
4116
+ barrier->set_value(config);
4117
+ });
4118
+ auto config = cb_wait_for_future(f);
4119
+ if (!config.has_value()) {
4120
+ rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get bucket configuration");
4121
+ return Qnil;
4122
+ }
4123
+ if (!config->supports_range_scan()) {
4124
+ rb_raise(eFeatureNotAvailable, "Server does not support key-value scan operations");
4125
+ return Qnil;
4126
+ }
4127
+ auto vbucket_map = config->vbmap;
4128
+ if (!vbucket_map || vbucket_map->empty()) {
4129
+ rb_raise(eCouchbaseError, "Cannot perform scan operation. Unable to get vbucket map");
4130
+ return Qnil;
4131
+ }
4132
+
4133
+ // Constructing the scan type
4134
+ std::variant<std::monostate, couchbase::core::range_scan, couchbase::core::prefix_scan, couchbase::core::sampling_scan>
4135
+ core_scan_type{};
4136
+ ID scan_type_id = rb_sym2id(rb_hash_aref(scan_type, rb_id2sym(rb_intern("scan_type"))));
4137
+ if (scan_type_id == rb_intern("range")) {
4138
+ auto range_scan = couchbase::core::range_scan{};
4139
+
4140
+ VALUE from_hash = rb_hash_aref(scan_type, rb_id2sym(rb_intern("from")));
4141
+ VALUE to_hash = rb_hash_aref(scan_type, rb_id2sym(rb_intern("to")));
4142
+
4143
+ if (!NIL_P(from_hash)) {
4144
+ Check_Type(from_hash, T_HASH);
4145
+ range_scan.from = couchbase::core::scan_term{};
4146
+ cb_extract_option_string(range_scan.from->term, from_hash, "term");
4147
+ cb_extract_option_bool(range_scan.from->exclusive, from_hash, "exclusive");
4148
+ }
4149
+ if (!NIL_P(to_hash)) {
4150
+ Check_Type(to_hash, T_HASH);
4151
+ range_scan.to = couchbase::core::scan_term{};
4152
+ cb_extract_option_string(range_scan.to->term, to_hash, "term");
4153
+ cb_extract_option_bool(range_scan.to->exclusive, to_hash, "exclusive");
4154
+ }
4155
+ core_scan_type = range_scan;
4156
+ } else if (scan_type_id == rb_intern("prefix")) {
4157
+ auto prefix_scan = couchbase::core::prefix_scan{};
4158
+ cb_extract_option_string(prefix_scan.prefix, scan_type, "prefix");
4159
+ core_scan_type = prefix_scan;
4160
+ } else if (scan_type_id == rb_intern("sampling")) {
4161
+ auto sampling_scan = couchbase::core::sampling_scan{};
4162
+ cb_extract_option_number(sampling_scan.limit, scan_type, "limit");
4163
+ cb_extract_option_number(sampling_scan.seed, scan_type, "seed");
4164
+ core_scan_type = sampling_scan;
4165
+ } else {
4166
+ rb_raise(eInvalidArgument, "Invalid scan operation type");
4167
+ }
4168
+
4169
+ auto orchestrator = couchbase::core::range_scan_orchestrator(
4170
+ cluster->io_context(), agent.value(), vbucket_map.value(), scope_name, collection_name, core_scan_type, orchestrator_options);
4171
+
4172
+ // Start the scan
4173
+ auto resp = orchestrator.scan();
4174
+ if (!resp.has_value()) {
4175
+ cb_throw_error_code(resp.error(), "unable to start scan");
4176
+ }
4177
+
4178
+ // Wrap core scan_result inside Ruby ScanResult
4179
+ // Creating a Ruby CoreScanResult object *after* checking that no error occurred during orchestrator.scan()
4180
+ VALUE cCoreScanResult = rb_define_class_under(rb_define_module("Couchbase"), "CoreScanResult", rb_cObject);
4181
+ rb_define_alloc_func(cCoreScanResult, cb_CoreScanResult_allocate);
4182
+ rb_define_method(cCoreScanResult, "next_item", VALUE_FUNC(cb_CoreScanResult_next_item), 0);
4183
+ rb_define_method(cCoreScanResult, "cancelled?", VALUE_FUNC(cb_CoreScanResult_is_cancelled), 0);
4184
+ rb_define_method(cCoreScanResult, "cancel", VALUE_FUNC(cb_CoreScanResult_cancel), 0);
4185
+ VALUE core_scan_result_obj = rb_class_new_instance(0, NULL, cCoreScanResult);
4186
+ rb_ivar_set(core_scan_result_obj, rb_intern("@backend"), self);
4187
+ cb_core_scan_result_data* data = nullptr;
4188
+ TypedData_Get_Struct(core_scan_result_obj, cb_core_scan_result_data, &cb_core_scan_result_type, data);
4189
+ data->scan_result = std::make_unique<couchbase::core::scan_result>(resp.value());
4190
+ return core_scan_result_obj;
4191
+
4192
+ } catch (const std::system_error& se) {
4193
+ rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
4194
+ } catch (const ruby_exception& e) {
4195
+ rb_exc_raise(e.exception_object());
4196
+ }
4197
+ return Qnil;
4198
+ }
4199
+
3665
4200
  static int
3666
4201
  cb_for_each_named_param(VALUE key, VALUE value, VALUE arg)
3667
4202
  {
@@ -3697,6 +4232,7 @@ cb_Backend_document_query(VALUE self, VALUE statement, VALUE options)
3697
4232
  cb_extract_option_bool(req.readonly, options, "readonly");
3698
4233
  cb_extract_option_bool(req.flex_index, options, "flex_index");
3699
4234
  cb_extract_option_bool(req.preserve_expiry, options, "preserve_expiry");
4235
+ cb_extract_option_bool(req.use_replica, options, "use_replica");
3700
4236
  cb_extract_option_uint64(req.scan_cap, options, "scan_cap");
3701
4237
  cb_extract_duration(req.scan_wait, options, "scan_wait");
3702
4238
  cb_extract_option_uint64(req.max_parallelism, options, "max_parallelism");
@@ -5090,6 +5626,14 @@ cb_Backend_query_index_get_all(VALUE self, VALUE bucket_name, VALUE options)
5090
5626
  couchbase::core::operations::management::query_index_get_all_request req{};
5091
5627
  req.bucket_name = cb_string_new(bucket_name);
5092
5628
  cb_extract_timeout(req, options);
5629
+ if (!NIL_P(options)) {
5630
+ if (VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name"))); TYPE(scope_name) == T_STRING) {
5631
+ req.scope_name = cb_string_new(scope_name);
5632
+ }
5633
+ if (VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name"))); TYPE(collection_name) == T_STRING) {
5634
+ req.collection_name = cb_string_new(collection_name);
5635
+ }
5636
+ }
5093
5637
  auto barrier = std::make_shared<std::promise<couchbase::core::operations::management::query_index_get_all_response>>();
5094
5638
  auto f = barrier->get_future();
5095
5639
  cluster->execute(req, [barrier](couchbase::core::operations::management::query_index_get_all_response&& resp) {
@@ -5466,15 +6010,50 @@ cb_Backend_query_index_build_deferred(VALUE self, VALUE bucket_name, VALUE optio
5466
6010
  }
5467
6011
 
5468
6012
  try {
5469
- couchbase::build_query_index_options opts;
5470
- couchbase::ruby::set_timeout(opts, options);
5471
- auto bucket = cb_string_new(bucket_name);
6013
+ couchbase::core::operations::management::query_index_build_deferred_request req{};
6014
+ cb_extract_timeout(req, options);
6015
+ req.bucket_name = cb_string_new(bucket_name);
5472
6016
 
5473
- auto f = couchbase::cluster(cluster).query_indexes().build_deferred_indexes(bucket, opts);
5474
- if (auto ctx = cb_wait_for_future(f); ctx.ec()) {
5475
- cb_throw_error_code(ctx, fmt::format("unable to trigger build for deferred indexes for the bucket \"{}\"", bucket));
6017
+ if (!NIL_P(options)) {
6018
+ if (VALUE scope_name = rb_hash_aref(options, rb_id2sym(rb_intern("scope_name"))); TYPE(scope_name) == T_STRING) {
6019
+ req.scope_name = cb_string_new(scope_name);
6020
+ }
6021
+ if (VALUE collection_name = rb_hash_aref(options, rb_id2sym(rb_intern("collection_name"))); TYPE(collection_name) == T_STRING) {
6022
+ req.collection_name = cb_string_new(collection_name);
6023
+ }
5476
6024
  }
5477
- return Qtrue;
6025
+
6026
+ auto barrier = std::make_shared<std::promise<couchbase::core::operations::management::query_index_build_deferred_response>>();
6027
+ auto f = barrier->get_future();
6028
+ cluster->execute(req, [barrier](couchbase::core::operations::management::query_index_build_deferred_response&& resp) {
6029
+ barrier->set_value(std::move(resp));
6030
+ });
6031
+ auto resp = cb_wait_for_future(f);
6032
+ if (resp.ctx.ec) {
6033
+ if (!resp.errors.empty()) {
6034
+ const auto& first_error = resp.errors.front();
6035
+ cb_throw_error_code(resp.ctx,
6036
+ fmt::format(R"(unable to build deferred indexes on the bucket "{}" ({}: {}))",
6037
+ req.bucket_name,
6038
+ first_error.code,
6039
+ first_error.message));
6040
+ } else {
6041
+ cb_throw_error_code(resp.ctx, fmt::format(R"(unable to build deferred indexes on the bucket "{}")", req.bucket_name));
6042
+ }
6043
+ }
6044
+ VALUE res = rb_hash_new();
6045
+ rb_hash_aset(res, rb_id2sym(rb_intern("status")), cb_str_new(resp.status));
6046
+ if (!resp.errors.empty()) {
6047
+ VALUE errors = rb_ary_new_capa(static_cast<long>(resp.errors.size()));
6048
+ for (const auto& err : resp.errors) {
6049
+ VALUE error = rb_hash_new();
6050
+ rb_hash_aset(error, rb_id2sym(rb_intern("code")), ULL2NUM(err.code));
6051
+ rb_hash_aset(error, rb_id2sym(rb_intern("message")), cb_str_new(err.message));
6052
+ rb_ary_push(errors, error);
6053
+ }
6054
+ rb_hash_aset(res, rb_id2sym(rb_intern("errors")), errors);
6055
+ }
6056
+ return res;
5478
6057
  } catch (const std::system_error& se) {
5479
6058
  rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
5480
6059
  } catch (const ruby_exception& e) {
@@ -8535,10 +9114,20 @@ cb_Backend_form_encode(VALUE self, VALUE data)
8535
9114
  return cb_str_new(encoded);
8536
9115
  }
8537
9116
 
9117
+ static VALUE
9118
+ cb_Backend_enable_protocol_logger_to_save_network_traffic_to_file(VALUE /* self */, VALUE path)
9119
+ {
9120
+ Check_Type(path, T_STRING);
9121
+ couchbase::core::logger::configuration configuration{};
9122
+ configuration.filename = cb_string_new(path);
9123
+ couchbase::core::logger::create_protocol_logger(configuration);
9124
+ return Qnil;
9125
+ }
9126
+
8538
9127
  static void
8539
9128
  init_backend(VALUE mCouchbase)
8540
9129
  {
8541
- VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cBasicObject);
9130
+ VALUE cBackend = rb_define_class_under(mCouchbase, "Backend", rb_cObject);
8542
9131
  rb_define_alloc_func(cBackend, cb_Backend_allocate);
8543
9132
  rb_define_method(cBackend, "open", VALUE_FUNC(cb_Backend_open), 3);
8544
9133
  rb_define_method(cBackend, "close", VALUE_FUNC(cb_Backend_close), 0);
@@ -8562,7 +9151,10 @@ init_backend(VALUE mCouchbase)
8562
9151
  rb_define_method(cBackend, "document_remove", VALUE_FUNC(cb_Backend_document_remove), 5);
8563
9152
  rb_define_method(cBackend, "document_remove_multi", VALUE_FUNC(cb_Backend_document_remove_multi), 5);
8564
9153
  rb_define_method(cBackend, "document_lookup_in", VALUE_FUNC(cb_Backend_document_lookup_in), 6);
9154
+ rb_define_method(cBackend, "document_lookup_in_any_replica", VALUE_FUNC(cb_Backend_document_lookup_in_any_replica), 6);
9155
+ rb_define_method(cBackend, "document_lookup_in_all_replicas", VALUE_FUNC(cb_Backend_document_lookup_in_all_replicas), 6);
8565
9156
  rb_define_method(cBackend, "document_mutate_in", VALUE_FUNC(cb_Backend_document_mutate_in), 6);
9157
+ rb_define_method(cBackend, "document_scan_create", VALUE_FUNC(cb_Backend_document_scan_create), 5);
8566
9158
  rb_define_method(cBackend, "document_query", VALUE_FUNC(cb_Backend_document_query), 2);
8567
9159
  rb_define_method(cBackend, "document_touch", VALUE_FUNC(cb_Backend_document_touch), 6);
8568
9160
  rb_define_method(cBackend, "document_exists", VALUE_FUNC(cb_Backend_document_exists), 5);
@@ -8664,6 +9256,10 @@ init_backend(VALUE mCouchbase)
8664
9256
  rb_define_singleton_method(cBackend, "query_escape", VALUE_FUNC(cb_Backend_query_escape), 1);
8665
9257
  rb_define_singleton_method(cBackend, "path_escape", VALUE_FUNC(cb_Backend_path_escape), 1);
8666
9258
  rb_define_singleton_method(cBackend, "form_encode", VALUE_FUNC(cb_Backend_form_encode), 1);
9259
+ rb_define_singleton_method(cBackend,
9260
+ "enable_protocol_logger_to_save_network_traffic_to_file",
9261
+ VALUE_FUNC(cb_Backend_enable_protocol_logger_to_save_network_traffic_to_file),
9262
+ 1);
8667
9263
  }
8668
9264
 
8669
9265
  void