couchbase 3.4.2 → 3.4.4

Sign up to get free protection for your applications and to get access to all the features.
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