couchbase 3.8.2 → 3.9.1

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 (473) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/ext/CMakeLists.txt +16 -1
  4. data/ext/cache/cpm/{CPM_0.42.0.cmake → CPM_0.43.1.cmake} +18 -2
  5. data/ext/cache/extconf_include.rb +6 -6
  6. data/ext/cache/mozilla-ca-bundle.crt +121 -55
  7. data/ext/cache/mozilla-ca-bundle.sha256 +1 -1
  8. data/ext/couchbase/CMakeLists.txt +136 -23
  9. data/ext/couchbase/cmake/APKBUILD.in +25 -4
  10. data/ext/couchbase/cmake/Bundler.cmake +143 -34
  11. data/ext/couchbase/cmake/CPM.cmake +126 -12
  12. data/ext/couchbase/cmake/Cache.cmake +7 -1
  13. data/ext/couchbase/cmake/CompilerOptions.cmake +1 -1
  14. data/ext/couchbase/cmake/CompilerWarnings.cmake +17 -6
  15. data/ext/couchbase/cmake/GrpcProtobuf.cmake +481 -0
  16. data/ext/couchbase/cmake/OpenSSL.cmake +82 -7
  17. data/ext/couchbase/cmake/Packaging.cmake +519 -65
  18. data/ext/couchbase/cmake/Protostellar.cmake +250 -0
  19. data/ext/couchbase/cmake/Sanitizers.cmake +61 -50
  20. data/ext/couchbase/cmake/StaticAnalyzers.cmake +16 -5
  21. data/ext/couchbase/cmake/TestFramework.cmake +283 -0
  22. data/ext/couchbase/cmake/TestFrameworkAddTests.cmake +51 -0
  23. data/ext/couchbase/cmake/Testing.cmake +27 -9
  24. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +141 -8
  25. data/ext/couchbase/cmake/VersionInfo.cmake +50 -0
  26. data/ext/couchbase/cmake/build_config.hxx.in +2 -1
  27. data/ext/couchbase/cmake/couchbase-cxx-client.spec.in +101 -23
  28. data/ext/couchbase/cmake/couchbase_cxx_client_static-config.cmake.in +7 -0
  29. data/ext/couchbase/cmake/couchbase_cxx_client_static.pc.in +2 -0
  30. data/ext/couchbase/cmake/gRPC_Generate.cmake +58 -0
  31. data/ext/couchbase/cmake/protobuf_Generate.cmake +69 -0
  32. data/ext/couchbase/cmake/require-git-checkout.cmake +25 -0
  33. data/ext/couchbase/cmake/tarball_glob.txt +49 -0
  34. data/ext/couchbase/core/agent_group.cxx +0 -8
  35. data/ext/couchbase/core/agent_group.hxx +0 -4
  36. data/ext/couchbase/core/analytics_stream.cxx +314 -0
  37. data/ext/couchbase/core/analytics_stream.hxx +129 -0
  38. data/ext/couchbase/core/analytics_stream_component.cxx +245 -0
  39. data/ext/couchbase/core/analytics_stream_component.hxx +67 -0
  40. data/ext/couchbase/core/app_telemetry_meter.cxx +25 -3
  41. data/ext/couchbase/core/app_telemetry_meter.hxx +77 -0
  42. data/ext/couchbase/core/app_telemetry_reporter.cxx +7 -6
  43. data/ext/couchbase/core/bucket.cxx +381 -87
  44. data/ext/couchbase/core/bucket.hxx +105 -25
  45. data/ext/couchbase/core/bucket_unit_test_api.hxx +57 -0
  46. data/ext/couchbase/core/capella.hxx +91 -0
  47. data/ext/couchbase/core/cluster.cxx +1551 -397
  48. data/ext/couchbase/core/cluster.hxx +39 -8
  49. data/ext/couchbase/core/cluster_agent.cxx +0 -8
  50. data/ext/couchbase/core/cluster_agent.hxx +0 -4
  51. data/ext/couchbase/core/cluster_options.hxx +26 -3
  52. data/ext/couchbase/core/collections_component.cxx +39 -15
  53. data/ext/couchbase/core/config_profiles.cxx +1 -1
  54. data/ext/couchbase/core/crud_component.cxx +2 -2
  55. data/ext/couchbase/core/crud_options.hxx +34 -0
  56. data/ext/couchbase/core/crypto/cbcrypto.cc +18 -13
  57. data/ext/couchbase/core/document_id_redaction.hxx +81 -0
  58. data/ext/couchbase/core/error_context/base_error_context.hxx +7 -6
  59. data/ext/couchbase/core/error_context/key_value.cxx +25 -2
  60. data/ext/couchbase/core/error_context/key_value.hxx +60 -33
  61. data/ext/couchbase/core/error_context/key_value_error_context.hxx +16 -15
  62. data/ext/couchbase/core/error_context/search.hxx +5 -0
  63. data/ext/couchbase/core/error_context/search_json.hxx +3 -0
  64. data/ext/couchbase/core/error_context/subdocument_error_context.hxx +19 -18
  65. data/ext/couchbase/core/error_context/view.hxx +5 -0
  66. data/ext/couchbase/core/free_form_http_request.cxx +237 -4
  67. data/ext/couchbase/core/free_form_http_request.hxx +41 -8
  68. data/ext/couchbase/core/http_component.cxx +300 -284
  69. data/ext/couchbase/core/http_component.hxx +0 -4
  70. data/ext/couchbase/core/impl/analytics.cxx +38 -5
  71. data/ext/couchbase/core/impl/analytics.hxx +34 -0
  72. data/ext/couchbase/core/impl/bootstrap_error.hxx +0 -3
  73. data/ext/couchbase/core/impl/collection.cxx +215 -202
  74. data/ext/couchbase/core/impl/collection_manager.cxx +1 -1
  75. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +45 -18
  76. data/ext/couchbase/core/impl/error.cxx +22 -2
  77. data/ext/couchbase/core/impl/internal_analytics_stream_result.hxx +111 -0
  78. data/ext/couchbase/core/impl/internal_query_stream_result.hxx +110 -0
  79. data/ext/couchbase/core/impl/invoke_with_node_id.hxx +15 -7
  80. data/ext/couchbase/core/impl/key_value_error_category.cxx +6 -0
  81. data/ext/couchbase/core/impl/lookup_in_replica.cxx +10 -10
  82. data/ext/couchbase/core/impl/lookup_in_replica.hxx +4 -4
  83. data/ext/couchbase/core/impl/node_id.cxx +49 -13
  84. data/ext/couchbase/core/impl/observability_recorder.cxx +12 -2
  85. data/ext/couchbase/core/impl/observe_poll.cxx +63 -23
  86. data/ext/couchbase/core/impl/public_analytics_stream_result.cxx +372 -0
  87. data/ext/couchbase/core/impl/public_bucket.cxx +48 -2
  88. data/ext/couchbase/core/impl/public_cluster.cxx +229 -42
  89. data/ext/couchbase/core/impl/public_query_stream_result.cxx +380 -0
  90. data/ext/couchbase/core/impl/public_transaction_get_multi_replicas_from_preferred_server_group_result.cxx +42 -0
  91. data/ext/couchbase/core/impl/public_transaction_get_multi_result.cxx +42 -0
  92. data/ext/couchbase/core/impl/query.cxx +76 -7
  93. data/ext/couchbase/core/impl/query.hxx +36 -0
  94. data/ext/couchbase/core/impl/query_index_manager.cxx +54 -1
  95. data/ext/couchbase/core/impl/replica_utils.cxx +101 -0
  96. data/ext/couchbase/core/impl/replica_utils.hxx +64 -0
  97. data/ext/couchbase/core/impl/resolve_node_id.hxx +125 -0
  98. data/ext/couchbase/core/impl/scope.cxx +70 -0
  99. data/ext/couchbase/core/impl/search.cxx +31 -1
  100. data/ext/couchbase/core/impl/transactions.cxx +130 -0
  101. data/ext/couchbase/core/impl/wait_until_ready.cxx +439 -0
  102. data/ext/couchbase/core/impl/wait_until_ready.hxx +110 -0
  103. data/ext/couchbase/core/impl/with_bucket_config_or_timeout.hxx +180 -0
  104. data/ext/couchbase/core/impl/with_cancellation.hxx +11 -3
  105. data/ext/couchbase/core/io/configuration_belongs_to_session.hxx +1 -2
  106. data/ext/couchbase/core/io/dns_client.cxx +122 -45
  107. data/ext/couchbase/core/io/dns_codec.hxx +21 -21
  108. data/ext/couchbase/core/io/dns_config.cxx +21 -6
  109. data/ext/couchbase/core/io/http_command.hxx +149 -121
  110. data/ext/couchbase/core/io/http_error.hxx +107 -0
  111. data/ext/couchbase/core/io/http_parser.cxx +4 -0
  112. data/ext/couchbase/core/io/http_session.cxx +606 -154
  113. data/ext/couchbase/core/io/http_session.hxx +147 -30
  114. data/ext/couchbase/core/io/http_session_manager.hxx +329 -382
  115. data/ext/couchbase/core/io/http_streaming_parser.cxx +4 -0
  116. data/ext/couchbase/core/io/http_streaming_response.cxx +328 -43
  117. data/ext/couchbase/core/io/http_streaming_response.hxx +37 -3
  118. data/ext/couchbase/core/io/mcbp_buffer_pool.hxx +122 -0
  119. data/ext/couchbase/core/io/mcbp_command.hxx +150 -51
  120. data/ext/couchbase/core/io/mcbp_command_id.hxx +45 -0
  121. data/ext/couchbase/core/io/mcbp_message.cxx +9 -1
  122. data/ext/couchbase/core/io/mcbp_message.hxx +19 -0
  123. data/ext/couchbase/core/io/mcbp_output_queue.hxx +150 -0
  124. data/ext/couchbase/core/io/mcbp_parser.cxx +24 -7
  125. data/ext/couchbase/core/io/mcbp_session.cxx +309 -301
  126. data/ext/couchbase/core/io/mcbp_session.hxx +27 -18
  127. data/ext/couchbase/core/io/opaque_ring_table.hxx +145 -0
  128. data/ext/couchbase/core/io/retry_orchestrator.hxx +6 -5
  129. data/ext/couchbase/core/io/stream_deadline.hxx +50 -0
  130. data/ext/couchbase/core/io/streams.cxx +151 -21
  131. data/ext/couchbase/core/io/streams.hxx +48 -1
  132. data/ext/couchbase/core/logger/logger.cxx +36 -0
  133. data/ext/couchbase/core/logger/logger.hxx +46 -6
  134. data/ext/couchbase/core/logger/redaction.hxx +503 -0
  135. data/ext/couchbase/core/management/eventing_status.hxx +10 -0
  136. data/ext/couchbase/core/management/eventing_status_json.hxx +4 -0
  137. data/ext/couchbase/core/mcbp/big_endian.cxx +1 -1
  138. data/ext/couchbase/core/mcbp/codec.cxx +27 -18
  139. data/ext/couchbase/core/mcbp/operation_queue.cxx +2 -2
  140. data/ext/couchbase/core/mcbp/packet.hxx +2 -2
  141. data/ext/couchbase/core/mcbp/queue_request.cxx +23 -6
  142. data/ext/couchbase/core/mcbp/queue_request.hxx +21 -0
  143. data/ext/couchbase/core/meta/features.hxx +13 -0
  144. data/ext/couchbase/core/meta/version.cxx +6 -3
  145. data/ext/couchbase/core/metrics/logging_meter.cxx +5 -10
  146. data/ext/couchbase/core/metrics/meter_wrapper.cxx +63 -33
  147. data/ext/couchbase/core/metrics/meter_wrapper.hxx +55 -3
  148. data/ext/couchbase/core/operations/analytics_response_parsing.cxx +177 -0
  149. data/ext/couchbase/core/operations/analytics_response_parsing.hxx +55 -0
  150. data/ext/couchbase/core/operations/document_analytics.cxx +48 -130
  151. data/ext/couchbase/core/operations/document_analytics.hxx +14 -2
  152. data/ext/couchbase/core/operations/document_get_all_replicas.hxx +15 -7
  153. data/ext/couchbase/core/operations/document_get_any_replica.hxx +19 -8
  154. data/ext/couchbase/core/operations/document_get_projected.cxx +1 -1
  155. data/ext/couchbase/core/{impl/get_replica.cxx → operations/document_get_replica.cxx} +21 -3
  156. data/ext/couchbase/core/{impl/get_replica.hxx → operations/document_get_replica.hxx} +31 -4
  157. data/ext/couchbase/core/operations/document_lookup_in.cxx +10 -10
  158. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +228 -198
  159. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +215 -217
  160. data/ext/couchbase/core/operations/document_query.cxx +108 -221
  161. data/ext/couchbase/core/operations/document_query.hxx +18 -4
  162. data/ext/couchbase/core/operations/document_search.cxx +52 -8
  163. data/ext/couchbase/core/operations/document_search.hxx +3 -0
  164. data/ext/couchbase/core/operations/document_view.cxx +3 -3
  165. data/ext/couchbase/core/operations/management/analytics_dataset_create.cxx +15 -8
  166. data/ext/couchbase/core/operations/management/analytics_dataset_create.hxx +4 -0
  167. data/ext/couchbase/core/operations/management/analytics_dataset_drop.cxx +11 -6
  168. data/ext/couchbase/core/operations/management/analytics_dataset_get_all.cxx +3 -2
  169. data/ext/couchbase/core/operations/management/analytics_dataverse_create.cxx +10 -5
  170. data/ext/couchbase/core/operations/management/analytics_dataverse_drop.cxx +10 -5
  171. data/ext/couchbase/core/operations/management/analytics_get_pending_mutations.cxx +2 -1
  172. data/ext/couchbase/core/operations/management/analytics_index_create.cxx +33 -8
  173. data/ext/couchbase/core/operations/management/analytics_index_drop.cxx +12 -7
  174. data/ext/couchbase/core/operations/management/analytics_index_get_all.cxx +3 -2
  175. data/ext/couchbase/core/operations/management/analytics_link_connect.cxx +11 -6
  176. data/ext/couchbase/core/operations/management/analytics_link_create.cxx +3 -3
  177. data/ext/couchbase/core/operations/management/analytics_link_disconnect.cxx +10 -4
  178. data/ext/couchbase/core/operations/management/analytics_link_drop.cxx +6 -4
  179. data/ext/couchbase/core/operations/management/analytics_link_get_all.cxx +4 -3
  180. data/ext/couchbase/core/operations/management/analytics_link_replace.cxx +3 -3
  181. data/ext/couchbase/core/operations/management/analytics_link_utils.hxx +1 -1
  182. data/ext/couchbase/core/operations/management/change_password.cxx +2 -0
  183. data/ext/couchbase/core/operations/management/collection_drop.cxx +5 -1
  184. data/ext/couchbase/core/operations/management/error_utils.cxx +60 -6
  185. data/ext/couchbase/core/operations/management/error_utils.hxx +29 -1
  186. data/ext/couchbase/core/operations/management/eventing_deploy_function.cxx +9 -3
  187. data/ext/couchbase/core/operations/management/eventing_drop_function.cxx +8 -3
  188. data/ext/couchbase/core/operations/management/eventing_get_all_functions.cxx +4 -2
  189. data/ext/couchbase/core/operations/management/eventing_get_function.cxx +5 -3
  190. data/ext/couchbase/core/operations/management/eventing_get_status.cxx +4 -2
  191. data/ext/couchbase/core/operations/management/eventing_pause_function.cxx +9 -3
  192. data/ext/couchbase/core/operations/management/eventing_resume_function.cxx +9 -3
  193. data/ext/couchbase/core/operations/management/eventing_undeploy_function.cxx +9 -3
  194. data/ext/couchbase/core/operations/management/eventing_upsert_function.cxx +9 -3
  195. data/ext/couchbase/core/operations/management/group_drop.cxx +3 -1
  196. data/ext/couchbase/core/operations/management/group_get.cxx +3 -1
  197. data/ext/couchbase/core/operations/management/group_upsert.cxx +11 -8
  198. data/ext/couchbase/core/operations/management/query_index_build.cxx +5 -2
  199. data/ext/couchbase/core/operations/management/query_index_create.cxx +9 -3
  200. data/ext/couchbase/core/operations/management/query_index_drop.cxx +11 -4
  201. data/ext/couchbase/core/operations/management/query_index_get_all.cxx +1 -1
  202. data/ext/couchbase/core/operations/management/query_index_get_all_deferred.cxx +1 -1
  203. data/ext/couchbase/core/operations/management/scope_drop.cxx +5 -1
  204. data/ext/couchbase/core/operations/management/scope_get_all.cxx +6 -1
  205. data/ext/couchbase/core/operations/management/search_get_stats.cxx +10 -0
  206. data/ext/couchbase/core/operations/management/search_index_analyze_document.cxx +3 -2
  207. data/ext/couchbase/core/operations/management/search_index_control_ingest.cxx +4 -3
  208. data/ext/couchbase/core/operations/management/search_index_control_plan_freeze.cxx +4 -3
  209. data/ext/couchbase/core/operations/management/search_index_control_query.cxx +4 -3
  210. data/ext/couchbase/core/operations/management/search_index_drop.cxx +2 -2
  211. data/ext/couchbase/core/operations/management/search_index_get.cxx +2 -2
  212. data/ext/couchbase/core/operations/management/search_index_get_documents_count.cxx +3 -2
  213. data/ext/couchbase/core/operations/management/search_index_get_stats.cxx +3 -1
  214. data/ext/couchbase/core/operations/management/search_index_upsert.cxx +2 -2
  215. data/ext/couchbase/core/operations/management/user_drop.cxx +3 -1
  216. data/ext/couchbase/core/operations/management/user_get.cxx +3 -1
  217. data/ext/couchbase/core/operations/management/user_upsert.cxx +12 -9
  218. data/ext/couchbase/core/operations/management/view_index_drop.cxx +1 -1
  219. data/ext/couchbase/core/operations/management/view_index_get.cxx +1 -1
  220. data/ext/couchbase/core/operations/management/view_index_upsert.cxx +1 -1
  221. data/ext/couchbase/core/operations/operation_traits.hxx +18 -0
  222. data/ext/couchbase/core/operations/query_response_parsing.cxx +211 -0
  223. data/ext/couchbase/core/operations/query_response_parsing.hxx +60 -0
  224. data/ext/couchbase/core/operations_fwd.hxx +3 -3
  225. data/ext/couchbase/core/origin.cxx +54 -26
  226. data/ext/couchbase/core/origin.hxx +12 -0
  227. data/ext/couchbase/core/orphan_reporter.cxx +2 -1
  228. data/ext/couchbase/core/platform/random.cc +7 -7
  229. data/ext/couchbase/core/protocol/client_request.cxx +2 -2
  230. data/ext/couchbase/core/protocol/client_request.hxx +38 -21
  231. data/ext/couchbase/core/protocol/client_response.cxx +11 -3
  232. data/ext/couchbase/core/protocol/client_response.hxx +27 -6
  233. data/ext/couchbase/core/protocol/cmd_append.cxx +2 -2
  234. data/ext/couchbase/core/protocol/cmd_cluster_map_change_notification.cxx +2 -2
  235. data/ext/couchbase/core/protocol/cmd_decrement.cxx +6 -6
  236. data/ext/couchbase/core/protocol/cmd_get.cxx +1 -1
  237. data/ext/couchbase/core/protocol/cmd_get_and_lock.cxx +2 -2
  238. data/ext/couchbase/core/protocol/cmd_get_and_touch.cxx +2 -2
  239. data/ext/couchbase/core/protocol/cmd_get_cluster_config.cxx +6 -4
  240. data/ext/couchbase/core/protocol/cmd_get_collection_id.cxx +2 -2
  241. data/ext/couchbase/core/protocol/cmd_get_error_map.cxx +1 -1
  242. data/ext/couchbase/core/protocol/cmd_get_meta.cxx +4 -4
  243. data/ext/couchbase/core/protocol/cmd_get_replica.cxx +1 -1
  244. data/ext/couchbase/core/protocol/cmd_hello.cxx +1 -1
  245. data/ext/couchbase/core/protocol/cmd_increment.cxx +6 -6
  246. data/ext/couchbase/core/protocol/cmd_insert.cxx +4 -4
  247. data/ext/couchbase/core/protocol/cmd_lookup_in.cxx +4 -3
  248. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +4 -3
  249. data/ext/couchbase/core/protocol/cmd_mutate_in.cxx +10 -9
  250. data/ext/couchbase/core/protocol/cmd_mutate_in.hxx +10 -10
  251. data/ext/couchbase/core/protocol/cmd_observe_seqno.cxx +7 -7
  252. data/ext/couchbase/core/protocol/cmd_prepend.cxx +2 -2
  253. data/ext/couchbase/core/protocol/cmd_remove.cxx +2 -2
  254. data/ext/couchbase/core/protocol/cmd_replace.cxx +4 -4
  255. data/ext/couchbase/core/protocol/cmd_touch.cxx +1 -1
  256. data/ext/couchbase/core/protocol/cmd_upsert.cxx +4 -4
  257. data/ext/couchbase/core/protocol/datatype.hxx +118 -1
  258. data/ext/couchbase/core/protocol/frame_info_utils.cxx +1 -1
  259. data/ext/couchbase/core/protocol/magic.hxx +4 -0
  260. data/ext/couchbase/core/protocol/magic_fmt.hxx +3 -0
  261. data/ext/couchbase/core/protocol/server_request.hxx +3 -1
  262. data/ext/couchbase/core/protocol/status.cxx +1 -1
  263. data/ext/couchbase/core/protostellar/analytics_converter.hxx +171 -0
  264. data/ext/couchbase/core/protostellar/bucket_admin_converter.hxx +301 -0
  265. data/ext/couchbase/core/protostellar/collection_admin_converter.hxx +92 -0
  266. data/ext/couchbase/core/protostellar/component.cxx +2445 -0
  267. data/ext/couchbase/core/protostellar/component.hxx +391 -0
  268. data/ext/couchbase/core/{columnar/bootstrap_notification_subscriber.hxx → protostellar/compression_settings.hxx} +11 -10
  269. data/ext/couchbase/core/protostellar/credentials.cxx +233 -0
  270. data/ext/couchbase/core/protostellar/credentials.hxx +88 -0
  271. data/ext/couchbase/core/protostellar/dispatcher.cxx +57 -0
  272. data/ext/couchbase/core/protostellar/dispatcher.hxx +482 -0
  273. data/ext/couchbase/core/protostellar/error_utils.cxx +293 -0
  274. data/ext/couchbase/core/protostellar/error_utils.hxx +97 -0
  275. data/ext/couchbase/core/protostellar/json_payload.hxx +49 -0
  276. data/ext/couchbase/core/protostellar/kv_converter.cxx +70 -0
  277. data/ext/couchbase/core/protostellar/kv_converter.hxx +600 -0
  278. data/ext/couchbase/core/protostellar/query_converter.hxx +265 -0
  279. data/ext/couchbase/core/protostellar/query_index_admin_converter.hxx +291 -0
  280. data/ext/couchbase/core/protostellar/query_proto.hxx +73 -0
  281. data/ext/couchbase/core/protostellar/search_converter.hxx +244 -0
  282. data/ext/couchbase/core/protostellar/search_index_admin_converter.hxx +156 -0
  283. data/ext/couchbase/core/protostellar/view_converter.hxx +158 -0
  284. data/ext/couchbase/core/query_stream.cxx +447 -0
  285. data/ext/couchbase/core/query_stream.hxx +141 -0
  286. data/ext/couchbase/core/query_stream_component.cxx +243 -0
  287. data/ext/couchbase/core/query_stream_component.hxx +68 -0
  288. data/ext/couchbase/core/range_scan_load_balancer.cxx +15 -8
  289. data/ext/couchbase/core/range_scan_orchestrator.cxx +15 -3
  290. data/ext/couchbase/core/response_handler.hxx +41 -4
  291. data/ext/couchbase/core/row_streamer.cxx +332 -46
  292. data/ext/couchbase/core/row_streamer.hxx +31 -1
  293. data/ext/couchbase/core/row_streamer_options.hxx +55 -0
  294. data/ext/couchbase/core/sasl/client.h +3 -0
  295. data/ext/couchbase/core/search_scoring.hxx +66 -0
  296. data/ext/couchbase/core/stream_error_details.hxx +69 -0
  297. data/ext/couchbase/core/timeout_defaults.hxx +0 -1
  298. data/ext/couchbase/core/topology/capabilities.hxx +6 -0
  299. data/ext/couchbase/core/topology/capabilities_fmt.hxx +3 -0
  300. data/ext/couchbase/core/topology/configuration.cxx +21 -6
  301. data/ext/couchbase/core/topology/configuration.hxx +29 -8
  302. data/ext/couchbase/core/topology/configuration_json.hxx +3 -0
  303. data/ext/couchbase/core/topology/error_map_json.hxx +3 -1
  304. data/ext/couchbase/core/tracing/threshold_logging_tracer.cxx +70 -4
  305. data/ext/couchbase/core/tracing/threshold_logging_tracer.hxx +10 -0
  306. data/ext/couchbase/core/transactions/active_transaction_record.cxx +0 -34
  307. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +108 -63
  308. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +19 -2
  309. data/ext/couchbase/core/transactions/error_list.hxx +2 -2
  310. data/ext/couchbase/core/transactions/get_multi_fetch.hxx +160 -0
  311. data/ext/couchbase/core/transactions/get_multi_orchestrator.cxx +326 -125
  312. data/ext/couchbase/core/transactions/get_multi_transaction_id.hxx +62 -0
  313. data/ext/couchbase/core/transactions/internal/atr_entry.hxx +22 -2
  314. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +2 -2
  315. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +23 -1
  316. data/ext/couchbase/core/transactions/internal/utils.hxx +50 -14
  317. data/ext/couchbase/core/transactions/staged_mutation.cxx +23 -18
  318. data/ext/couchbase/core/transactions/staged_mutation.hxx +15 -4
  319. data/ext/couchbase/core/transactions/transaction_context.cxx +55 -40
  320. data/ext/couchbase/core/transactions/transaction_get_result.hxx +16 -0
  321. data/ext/couchbase/core/transactions/transactions.cxx +3 -55
  322. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +165 -72
  323. data/ext/couchbase/core/transactions/transactions_config.cxx +0 -11
  324. data/ext/couchbase/core/transactions/utils.cxx +10 -0
  325. data/ext/couchbase/core/transactions/waitable_op_list.hxx +2 -2
  326. data/ext/couchbase/core/transactions.hxx +9 -9
  327. data/ext/couchbase/core/utils/byteswap.hxx +166 -9
  328. data/ext/couchbase/core/utils/connection_string.cxx +50 -85
  329. data/ext/couchbase/core/utils/connection_string.hxx +15 -0
  330. data/ext/couchbase/core/{columnar/backoff_calculator.hxx → utils/deadline.hxx} +13 -13
  331. data/ext/couchbase/core/utils/duration_parser.cxx +1 -1
  332. data/ext/couchbase/core/utils/json_streaming_lexer.cxx +48 -5
  333. data/ext/couchbase/core/utils/json_streaming_lexer.hxx +4 -1
  334. data/ext/couchbase/core/utils/movable_function.hxx +301 -52
  335. data/ext/couchbase/core/utils/name_codec.hxx +154 -11
  336. data/ext/couchbase/core/{columnar/retry_info.hxx → utils/process_id.hxx} +18 -13
  337. data/ext/couchbase/core/utils/url_codec.cxx +12 -51
  338. data/ext/couchbase/core/websocket_codec.cxx +13 -37
  339. data/ext/couchbase/couchbase/analytics_options.hxx +21 -10
  340. data/ext/couchbase/couchbase/analytics_row.hxx +105 -0
  341. data/ext/couchbase/couchbase/analytics_stream_result.hxx +266 -0
  342. data/ext/couchbase/couchbase/boolean_query.hxx +3 -3
  343. data/ext/couchbase/couchbase/bucket.hxx +57 -0
  344. data/ext/couchbase/couchbase/cluster.hxx +183 -5
  345. data/ext/couchbase/{core/columnar/security_options.hxx → couchbase/cluster_state.hxx} +18 -14
  346. data/ext/couchbase/couchbase/codec/lenient_json_transcoder.hxx +69 -0
  347. data/ext/couchbase/couchbase/collection.hxx +234 -14
  348. data/ext/couchbase/couchbase/common_durability_options.hxx +18 -3
  349. data/ext/couchbase/couchbase/conjunction_query.hxx +1 -1
  350. data/ext/couchbase/couchbase/create_dataset_analytics_options.hxx +6 -1
  351. data/ext/couchbase/couchbase/date_range_query.hxx +2 -2
  352. data/ext/couchbase/couchbase/decrement_options.hxx +1 -1
  353. data/ext/couchbase/couchbase/disjunction_query.hxx +1 -1
  354. data/ext/couchbase/couchbase/error.hxx +32 -0
  355. data/ext/couchbase/couchbase/error_codes.hxx +33 -1
  356. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +1 -1
  357. data/ext/couchbase/couchbase/geo_distance_query.hxx +1 -1
  358. data/ext/couchbase/couchbase/geo_polygon_query.hxx +1 -1
  359. data/ext/couchbase/couchbase/get_replica_options.hxx +68 -0
  360. data/ext/couchbase/couchbase/get_replica_result.hxx +5 -3
  361. data/ext/couchbase/couchbase/get_replica_strategy.hxx +161 -0
  362. data/ext/couchbase/couchbase/get_result.hxx +1 -0
  363. data/ext/couchbase/couchbase/increment_options.hxx +1 -1
  364. data/ext/couchbase/couchbase/insert_options.hxx +1 -1
  365. data/ext/couchbase/couchbase/match_phrase_query.hxx +1 -1
  366. data/ext/couchbase/couchbase/match_query.hxx +1 -1
  367. data/ext/couchbase/couchbase/mutate_in_options.hxx +3 -3
  368. data/ext/couchbase/couchbase/network_options.hxx +1 -1
  369. data/ext/couchbase/couchbase/node_id.hxx +42 -14
  370. data/ext/couchbase/couchbase/node_id_for_options.hxx +7 -1
  371. data/ext/couchbase/couchbase/node_ids_options.hxx +8 -2
  372. data/ext/couchbase/couchbase/numeric_range_query.hxx +1 -1
  373. data/ext/couchbase/couchbase/phrase_query.hxx +1 -1
  374. data/ext/couchbase/couchbase/prefix_query.hxx +1 -1
  375. data/ext/couchbase/couchbase/query_options.hxx +23 -12
  376. data/ext/couchbase/couchbase/query_row.hxx +111 -0
  377. data/ext/couchbase/couchbase/query_stream_result.hxx +302 -0
  378. data/ext/couchbase/couchbase/query_string_query.hxx +3 -3
  379. data/ext/couchbase/couchbase/regexp_query.hxx +1 -1
  380. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  381. data/ext/couchbase/couchbase/result.hxx +14 -3
  382. data/ext/couchbase/couchbase/scan_result_item.hxx +1 -0
  383. data/ext/couchbase/couchbase/scope.hxx +85 -2
  384. data/ext/couchbase/couchbase/search_options.hxx +58 -8
  385. data/ext/couchbase/couchbase/search_scoring.hxx +94 -0
  386. data/ext/couchbase/couchbase/search_scoring_none.hxx +51 -0
  387. data/ext/couchbase/couchbase/search_scoring_reciprocal_rank_fusion.hxx +88 -0
  388. data/ext/couchbase/couchbase/search_scoring_relative_score_fusion.hxx +70 -0
  389. data/ext/couchbase/couchbase/term_range_query.hxx +1 -1
  390. data/ext/couchbase/couchbase/tracing/request_span.hxx +46 -0
  391. data/ext/couchbase/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +23 -21
  392. data/ext/couchbase/couchbase/transactions/transaction_get_multi_result.hxx +24 -19
  393. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +17 -3
  394. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +4 -2
  395. data/ext/couchbase/couchbase/transactions.hxx +27 -18
  396. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  397. data/ext/couchbase/couchbase/vector_query.hxx +1 -1
  398. data/ext/couchbase/couchbase/wait_until_ready_options.hxx +111 -0
  399. data/ext/couchbase/couchbase/wildcard_query.hxx +1 -1
  400. data/ext/extconf.rb +15 -10
  401. data/ext/rcb_analytics.cxx +82 -102
  402. data/ext/rcb_backend.cxx +42 -36
  403. data/ext/rcb_backend.hxx +2 -0
  404. data/ext/rcb_buckets.cxx +47 -59
  405. data/ext/rcb_collections.cxx +42 -52
  406. data/ext/rcb_crud.cxx +345 -224
  407. data/ext/rcb_diagnostics.cxx +117 -27
  408. data/ext/rcb_exceptions.cxx +152 -99
  409. data/ext/rcb_exceptions.hxx +25 -0
  410. data/ext/rcb_extras.cxx +18 -19
  411. data/ext/rcb_hdr_histogram.cxx +19 -4
  412. data/ext/rcb_logger.cxx +202 -27
  413. data/ext/rcb_logger.hxx +12 -0
  414. data/ext/rcb_multi.cxx +40 -40
  415. data/ext/rcb_observability.cxx +7 -5
  416. data/ext/rcb_query.cxx +99 -142
  417. data/ext/rcb_range_scan.cxx +41 -35
  418. data/ext/rcb_search.cxx +98 -99
  419. data/ext/rcb_users.cxx +36 -56
  420. data/ext/rcb_utils.cxx +100 -37
  421. data/ext/rcb_utils.hxx +287 -33
  422. data/ext/rcb_version.cxx +1 -1
  423. data/ext/rcb_views.cxx +55 -51
  424. data/lib/active_support/cache/couchbase_store.rb +77 -12
  425. data/lib/couchbase/bucket.rb +20 -0
  426. data/lib/couchbase/cluster.rb +17 -0
  427. data/lib/couchbase/collection.rb +36 -1
  428. data/lib/couchbase/errors.rb +18 -0
  429. data/lib/couchbase/fork_hooks.rb +16 -7
  430. data/lib/couchbase/get_replica_strategy.rb +89 -0
  431. data/lib/couchbase/logger.rb +1 -1
  432. data/lib/couchbase/management/analytics_index_manager.rb +15 -15
  433. data/lib/couchbase/management/bucket_manager.rb +6 -6
  434. data/lib/couchbase/management/collection_manager.rb +6 -6
  435. data/lib/couchbase/management/query_index_manager.rb +7 -7
  436. data/lib/couchbase/management/search_index_manager.rb +13 -13
  437. data/lib/couchbase/management/user_manager.rb +10 -10
  438. data/lib/couchbase/management/view_index_manager.rb +5 -5
  439. data/lib/couchbase/options.rb +174 -42
  440. data/lib/couchbase/protostellar/bucket.rb +4 -0
  441. data/lib/couchbase/protostellar/cluster.rb +4 -0
  442. data/lib/couchbase/protostellar/collection.rb +4 -0
  443. data/lib/couchbase/protostellar/error_handling.rb +2 -1
  444. data/lib/couchbase/protostellar/request.rb +1 -0
  445. data/lib/couchbase/protostellar/request_generator/kv.rb +16 -2
  446. data/lib/couchbase/protostellar/request_generator/search.rb +17 -1
  447. data/lib/couchbase/protostellar/retry/orchestrator.rb +3 -2
  448. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  449. data/lib/couchbase/protostellar/retry/strategies.rb +1 -0
  450. data/lib/couchbase/search_options.rb +95 -6
  451. data/lib/couchbase/version.rb +1 -1
  452. metadata +91 -33
  453. data/ext/0001-fix-build-for-mingw-w64-ucrt-x86_64-toolchain.patch +0 -40
  454. data/ext/couchbase/core/columnar/agent.hxx +0 -71
  455. data/ext/couchbase/core/columnar/agent_config.hxx +0 -59
  456. data/ext/couchbase/core/columnar/background_bootstrap_listener.hxx +0 -42
  457. data/ext/couchbase/core/columnar/backoff_calculator.cxx +0 -62
  458. data/ext/couchbase/core/columnar/columnar_agent.cxx +0 -147
  459. data/ext/couchbase/core/columnar/columnar_agent_config.cxx +0 -48
  460. data/ext/couchbase/core/columnar/columnar_error.cxx +0 -51
  461. data/ext/couchbase/core/columnar/database_management_options.hxx +0 -56
  462. data/ext/couchbase/core/columnar/error.hxx +0 -51
  463. data/ext/couchbase/core/columnar/error_codes.cxx +0 -107
  464. data/ext/couchbase/core/columnar/error_codes.hxx +0 -75
  465. data/ext/couchbase/core/columnar/management_component.cxx +0 -300
  466. data/ext/couchbase/core/columnar/management_component.hxx +0 -56
  467. data/ext/couchbase/core/columnar/query_component.cxx +0 -523
  468. data/ext/couchbase/core/columnar/query_component.hxx +0 -57
  469. data/ext/couchbase/core/columnar/query_options.hxx +0 -59
  470. data/ext/couchbase/core/columnar/query_result.cxx +0 -130
  471. data/ext/couchbase/core/columnar/query_result.hxx +0 -78
  472. data/ext/couchbase/core/io/config_tracker.cxx +0 -687
  473. data/ext/couchbase/core/io/config_tracker.hxx +0 -123
@@ -0,0 +1,380 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2026. Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <couchbase/error_codes.hxx>
19
+ #include <couchbase/query_meta_data.hxx>
20
+ #include <couchbase/query_metrics.hxx>
21
+ #include <couchbase/query_status.hxx>
22
+ #include <couchbase/query_stream_result.hxx>
23
+ #include <couchbase/query_warning.hxx>
24
+
25
+ #include "core/operations/document_query.hxx"
26
+ #include "core/utils/binary.hxx"
27
+
28
+ #include "error.hxx"
29
+ #include "internal_query_stream_result.hxx"
30
+ #include "observability_recorder.hxx"
31
+ #include "query.hxx"
32
+
33
+ #include <future>
34
+ #include <memory>
35
+ #include <mutex>
36
+ #include <optional>
37
+ #include <string>
38
+ #include <system_error>
39
+ #include <utility>
40
+ #include <vector>
41
+
42
+ namespace couchbase
43
+ {
44
+ namespace
45
+ {
46
+ auto
47
+ to_binary(const std::string& s) -> codec::binary
48
+ {
49
+ return core::utils::to_binary(s);
50
+ }
51
+
52
+ auto
53
+ build_query_meta_data(core::operations::query_response::query_meta_data meta) -> query_meta_data
54
+ {
55
+ std::vector<query_warning> warnings;
56
+ if (meta.warnings) {
57
+ warnings.reserve(meta.warnings->size());
58
+ for (auto& w : *meta.warnings) {
59
+ warnings.emplace_back(w.code, std::move(w.message), w.reason, w.retry);
60
+ }
61
+ }
62
+
63
+ std::optional<query_metrics> metrics;
64
+ if (meta.metrics) {
65
+ metrics = query_metrics{
66
+ meta.metrics->elapsed_time, meta.metrics->execution_time, meta.metrics->result_count,
67
+ meta.metrics->result_size, meta.metrics->sort_count, meta.metrics->mutation_count,
68
+ meta.metrics->error_count, meta.metrics->warning_count,
69
+ };
70
+ }
71
+
72
+ std::optional<codec::binary> signature;
73
+ if (meta.signature) {
74
+ signature = to_binary(*meta.signature);
75
+ }
76
+
77
+ std::optional<codec::binary> profile;
78
+ if (meta.profile) {
79
+ profile = to_binary(*meta.profile);
80
+ }
81
+
82
+ return query_meta_data{
83
+ std::move(meta.request_id),
84
+ std::move(meta.client_context_id),
85
+ core::impl::map_query_status(std::move(meta.status)),
86
+ std::move(warnings),
87
+ metrics,
88
+ std::move(signature),
89
+ std::move(profile),
90
+ };
91
+ }
92
+ } // namespace
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // internal_query_stream_result implementation
96
+ // ---------------------------------------------------------------------------
97
+
98
+ internal_query_stream_result::internal_query_stream_result(
99
+ core::query_stream stream,
100
+ std::unique_ptr<core::impl::observability_recorder> obs_rec,
101
+ core::error_context::query ctx)
102
+ : stream_{ std::move(stream) }
103
+ , ctx_{ std::move(ctx) }
104
+ , obs_rec_{ std::move(obs_rec) }
105
+ {
106
+ }
107
+
108
+ internal_query_stream_result::~internal_query_stream_result()
109
+ {
110
+ cancel();
111
+ }
112
+
113
+ void
114
+ internal_query_stream_result::cancel()
115
+ {
116
+ // Resolve any parked meta_data() futures with a cancellation error so they don't throw
117
+ // broken_promise when the stream is torn down before reaching a natural terminal. Idempotent
118
+ // via terminal_reached_, so a real terminal that already ran is preserved.
119
+ resolve_meta_data(errc::common::request_canceled);
120
+ stream_.cancel();
121
+ }
122
+
123
+ auto
124
+ internal_query_stream_result::signature() const -> std::optional<codec::binary>
125
+ {
126
+ auto raw = stream_.signature();
127
+ if (!raw) {
128
+ return {};
129
+ }
130
+ return to_binary(*raw);
131
+ }
132
+
133
+ void
134
+ internal_query_stream_result::resolve_meta_data(std::error_code ec)
135
+ {
136
+ std::pair<error, query_meta_data> value;
137
+ if (ec) {
138
+ // Report the terminal against the request's context with whatever the response said stamped on,
139
+ // so a mid-stream failure carries the same detail (statement, service error, endpoint) as one
140
+ // that never started. A cancellation leaves the service error code and message unset, because
141
+ // the service never reported one, but the envelope parsed so far is still reported as the body:
142
+ // it names the request id the service logs are keyed by, and the buffered path likewise reports
143
+ // whatever body it received.
144
+ auto ctx = ctx_;
145
+ ctx.ec = ec;
146
+ core::apply_error_details(ctx, stream_.error_details());
147
+ value.first = core::impl::make_error(ctx);
148
+ }
149
+ auto core_meta = stream_.meta_data();
150
+ if (core_meta) {
151
+ value.second = build_query_meta_data(std::move(*core_meta));
152
+ }
153
+
154
+ std::vector<std::promise<std::pair<error, query_meta_data>>> to_satisfy;
155
+ {
156
+ const std::scoped_lock lk{ meta_mutex_ };
157
+ if (terminal_reached_) {
158
+ return;
159
+ }
160
+ terminal_reached_ = true;
161
+ terminal_value_ = value;
162
+ to_satisfy = std::move(pending_meta_promises_);
163
+ pending_meta_promises_.clear();
164
+ }
165
+ for (auto& promise : to_satisfy) {
166
+ promise.set_value(value);
167
+ }
168
+ // Reached exactly once (the terminal_reached_ guard above returns on every later call), so the
169
+ // operation is finished here: record the latency metric and end the operation span. ec is the
170
+ // terminal error (falsy on a clean drain, request_canceled on teardown before a natural end).
171
+ if (obs_rec_) {
172
+ obs_rec_->finish(ec);
173
+ }
174
+ }
175
+
176
+ auto
177
+ internal_query_stream_result::meta_data() -> std::future<std::pair<error, query_meta_data>>
178
+ {
179
+ const std::scoped_lock lk{ meta_mutex_ };
180
+ std::promise<std::pair<error, query_meta_data>> promise;
181
+ auto future = promise.get_future();
182
+ if (terminal_reached_) {
183
+ promise.set_value(terminal_value_);
184
+ } else {
185
+ pending_meta_promises_.push_back(std::move(promise));
186
+ }
187
+ return future;
188
+ }
189
+
190
+ void
191
+ internal_query_stream_result::next(query_row_handler&& handler)
192
+ {
193
+ {
194
+ // Idempotent terminal: once the stream has ended, re-deliver the terminal (clean end or the
195
+ // terminal error) instead of issuing a pull that would block forever on the drained channel.
196
+ const std::scoped_lock lk{ meta_mutex_ };
197
+ if (terminal_reached_) {
198
+ return handler(terminal_value_.first, std::nullopt);
199
+ }
200
+ }
201
+ bool expected = false;
202
+ if (!pull_in_flight_.compare_exchange_strong(expected, true)) {
203
+ // Enforce the single-outstanding-next() contract instead of racing the single-consumer channel.
204
+ return handler(
205
+ error{ errc::common::invalid_argument, "a previous next() call is still in flight" },
206
+ std::nullopt);
207
+ }
208
+ // Capture a strong self so the object outlives an in-flight pull; dropping the public handle
209
+ // mid-pull would otherwise destroy this object before the channel completion runs (use-after-
210
+ // free). The stream is always owned via shared_ptr (make_shared in dispatch_query_stream).
211
+ stream_.next_row([handler = std::move(handler), self = shared_from_this()](
212
+ std::optional<std::string> row, std::error_code ec) mutable {
213
+ if (row.has_value()) {
214
+ // Real row (ec is falsy). Release the pull gate before invoking the handler so it may
215
+ // immediately issue the next pull.
216
+ self->pull_in_flight_.store(false);
217
+ return handler({}, query_row{ to_binary(*row) });
218
+ }
219
+ // Terminal (nullopt row): publish the terminal state and intentionally leave pull_in_flight_
220
+ // set. Every later next() is served by the terminal_reached_ guard (idempotent re-delivery) and
221
+ // must never issue another pull onto the drained channel, so the gate is never reopened — this
222
+ // also backstops a caller that violates the single-outstanding-next() contract from a racing
223
+ // thread before terminal_reached_ becomes visible.
224
+ self->resolve_meta_data(ec);
225
+ if (ec) {
226
+ // Deliver the contextual error resolve_meta_data() has just published rather than building a
227
+ // bare one here. This is the first and usually only observation of a mid-stream terminal, so
228
+ // it has to carry the same diagnostics as every later next() (served by the terminal_reached_
229
+ // guard above) and as meta_data(); constructing a fresh error here would report the one case
230
+ // this class exists to describe with an empty context.
231
+ error terminal_error;
232
+ {
233
+ const std::scoped_lock lk{ self->meta_mutex_ };
234
+ terminal_error = self->terminal_value_.first;
235
+ }
236
+ return handler(std::move(terminal_error), {});
237
+ }
238
+ return handler({}, {});
239
+ });
240
+ }
241
+
242
+ // ---------------------------------------------------------------------------
243
+ // query_stream_result public implementation
244
+ // ---------------------------------------------------------------------------
245
+
246
+ query_stream_result::query_stream_result(std::shared_ptr<internal_query_stream_result> internal)
247
+ : internal_{ std::move(internal) }
248
+ {
249
+ }
250
+
251
+ void
252
+ query_stream_result::next(query_row_handler&& handler) const
253
+ {
254
+ if (!internal_) {
255
+ // Empty handle behaves as an immediately-exhausted stream.
256
+ handler(error{}, std::nullopt);
257
+ return;
258
+ }
259
+ return internal_->next(std::move(handler));
260
+ }
261
+
262
+ auto
263
+ query_stream_result::next() const -> std::future<std::pair<error, std::optional<query_row>>>
264
+ {
265
+ auto barrier = std::make_shared<std::promise<std::pair<error, std::optional<query_row>>>>();
266
+ if (!internal_) {
267
+ // Empty handle behaves as an immediately-exhausted stream.
268
+ barrier->set_value({ error{}, std::nullopt });
269
+ return barrier->get_future();
270
+ }
271
+ internal_->next([barrier](const auto& err, const auto& row) mutable {
272
+ barrier->set_value({ err, row });
273
+ });
274
+ return barrier->get_future();
275
+ }
276
+
277
+ auto
278
+ query_stream_result::signature() const -> std::optional<codec::binary>
279
+ {
280
+ if (!internal_) {
281
+ return {};
282
+ }
283
+ return internal_->signature();
284
+ }
285
+
286
+ auto
287
+ query_stream_result::meta_data() const -> std::future<std::pair<error, query_meta_data>>
288
+ {
289
+ if (!internal_) {
290
+ // Empty handle resolves immediately with empty metadata.
291
+ std::promise<std::pair<error, query_meta_data>> p;
292
+ p.set_value({ error{}, query_meta_data{} });
293
+ return p.get_future();
294
+ }
295
+ return internal_->meta_data();
296
+ }
297
+
298
+ void
299
+ query_stream_result::cancel() const
300
+ {
301
+ if (internal_) {
302
+ return internal_->cancel();
303
+ }
304
+ }
305
+
306
+ // ---------------------------------------------------------------------------
307
+ // iterator implementation
308
+ // ---------------------------------------------------------------------------
309
+
310
+ query_stream_result::iterator::iterator(std::shared_ptr<internal_query_stream_result> internal)
311
+ : internal_{ std::move(internal) }
312
+ {
313
+ if (internal_) {
314
+ fetch_item();
315
+ } else {
316
+ // An empty result handle has no rows: the iterator starts already at end.
317
+ terminal_ = true;
318
+ }
319
+ }
320
+
321
+ void
322
+ query_stream_result::iterator::fetch_item()
323
+ {
324
+ auto barrier = std::make_shared<std::promise<std::pair<error, std::optional<query_row>>>>();
325
+ internal_->next([barrier](const error& err, std::optional<query_row> row) mutable {
326
+ barrier->set_value({ err, std::move(row) });
327
+ });
328
+ auto result = barrier->get_future().get();
329
+ if (result.first) {
330
+ // Terminal error: deliver it as one visible element (still != end()) so a range-for loop can
331
+ // observe it; the next increment then advances to true end.
332
+ item_ = { result.first, {} };
333
+ terminal_ = false;
334
+ error_pending_ = true;
335
+ } else if (!result.second.has_value()) {
336
+ // Clean end-of-stream.
337
+ item_ = {};
338
+ terminal_ = true;
339
+ error_pending_ = false;
340
+ } else {
341
+ item_ = { {}, *result.second };
342
+ terminal_ = false;
343
+ error_pending_ = false;
344
+ }
345
+ }
346
+
347
+ auto
348
+ query_stream_result::iterator::operator*() const -> std::pair<error, query_row>
349
+ {
350
+ return item_;
351
+ }
352
+
353
+ auto
354
+ query_stream_result::iterator::operator++() -> query_stream_result::iterator&
355
+ {
356
+ if (error_pending_) {
357
+ // The terminal error element has been consumed; advance to end().
358
+ error_pending_ = false;
359
+ item_ = {};
360
+ terminal_ = true;
361
+ return *this;
362
+ }
363
+ fetch_item();
364
+ return *this;
365
+ }
366
+
367
+ auto
368
+ query_stream_result::begin() const -> query_stream_result::iterator
369
+ {
370
+ // The iterator constructor treats a null internal handle as an already-drained stream, so an
371
+ // empty result handle yields begin() == end().
372
+ return query_stream_result::iterator{ internal_ };
373
+ }
374
+
375
+ auto
376
+ query_stream_result::end() const -> query_stream_result::end_sentinel
377
+ {
378
+ return {};
379
+ }
380
+ } // namespace couchbase
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Copyright 2021-Present Couchbase, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx>
18
+
19
+ #include <couchbase/codec/encoded_value.hxx>
20
+ #include <couchbase/error_codes.hxx>
21
+
22
+ #include <cstddef>
23
+ #include <stdexcept>
24
+ #include <string>
25
+ #include <system_error>
26
+
27
+ namespace couchbase::transactions
28
+ {
29
+ auto
30
+ transaction_get_multi_replicas_from_preferred_server_group_result::content_at(
31
+ std::size_t spec_index) const -> const codec::encoded_value&
32
+ {
33
+ if (spec_index >= content_.size()) {
34
+ throw std::invalid_argument("spec index " + std::to_string(spec_index) + " is not valid");
35
+ }
36
+ if (const auto& content = content_[spec_index]; content.has_value()) {
37
+ return content.value();
38
+ }
39
+ throw std::system_error(errc::key_value::document_not_found,
40
+ "document was not found for index " + std::to_string(spec_index));
41
+ }
42
+ } // namespace couchbase::transactions
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Copyright 2021-Present Couchbase, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <couchbase/transactions/transaction_get_multi_result.hxx>
18
+
19
+ #include <couchbase/codec/encoded_value.hxx>
20
+ #include <couchbase/error_codes.hxx>
21
+
22
+ #include <cstddef>
23
+ #include <stdexcept>
24
+ #include <string>
25
+ #include <system_error>
26
+
27
+ namespace couchbase::transactions
28
+ {
29
+ auto
30
+ transaction_get_multi_result::content_at(std::size_t spec_index) const
31
+ -> const codec::encoded_value&
32
+ {
33
+ if (spec_index >= content_.size()) {
34
+ throw std::invalid_argument("spec index " + std::to_string(spec_index) + " is not valid");
35
+ }
36
+ if (const auto& content = content_[spec_index]; content.has_value()) {
37
+ return content.value();
38
+ }
39
+ throw std::system_error(errc::key_value::document_not_found,
40
+ "document was not found for index " + std::to_string(spec_index));
41
+ }
42
+ } // namespace couchbase::transactions
@@ -18,22 +18,31 @@
18
18
  #include <couchbase/error_codes.hxx>
19
19
  #include <couchbase/query_options.hxx>
20
20
  #include <couchbase/transactions/transaction_query_result.hxx>
21
+
22
+ #include <algorithm>
23
+ #include <cctype>
21
24
  #include <utility>
22
25
 
23
26
  #include "core/cluster.hxx"
24
27
  #include "core/error_context/transaction_op_error_context.hxx"
28
+ #include "core/free_form_http_request.hxx"
25
29
  #include "core/operations/document_query.hxx"
30
+ #include "core/query_stream.hxx"
26
31
  #include "core/utils/binary.hxx"
32
+ #include "error.hxx"
33
+ #include "internal_query_stream_result.hxx"
34
+ #include "observability_recorder.hxx"
35
+ #include "query.hxx"
36
+
37
+ #include <memory>
27
38
 
28
39
  namespace couchbase::core::impl
29
40
  {
30
- namespace
31
- {
32
41
  auto
33
- map_status(std::string status) -> query_status
42
+ map_query_status(std::string status) -> query_status
34
43
  {
35
44
  std::transform(status.cbegin(), status.cend(), status.begin(), [](unsigned char c) {
36
- return std::tolower(c);
45
+ return static_cast<char>(std::tolower(c));
37
46
  });
38
47
  if (status == "running") {
39
48
  return query_status::running;
@@ -65,8 +74,10 @@ map_status(std::string status) -> query_status
65
74
  return query_status::unknown;
66
75
  }
67
76
 
77
+ namespace
78
+ {
68
79
  auto
69
- map_rows(operations::query_response& resp) -> std::vector<codec::binary>
80
+ map_rows(const operations::query_response& resp) -> std::vector<codec::binary>
70
81
  {
71
82
  std::vector<codec::binary> rows;
72
83
  rows.reserve(resp.rows.size());
@@ -154,7 +165,7 @@ build_result(operations::query_response& resp) -> query_result
154
165
  query_meta_data{
155
166
  std::move(resp.meta.request_id),
156
167
  std::move(resp.meta.client_context_id),
157
- map_status(resp.meta.status),
168
+ map_query_status(resp.meta.status),
158
169
  map_warnings(resp),
159
170
  map_metrics(resp),
160
171
  map_signature(resp),
@@ -201,6 +212,64 @@ build_query_request(std::string statement,
201
212
  return request;
202
213
  }
203
214
 
215
+ void
216
+ dispatch_query_stream(const core::cluster& core,
217
+ core::operations::query_request request,
218
+ std::unique_ptr<observability_recorder> obs_rec,
219
+ query_stream_handler&& handler)
220
+ {
221
+ if (!request.adhoc) {
222
+ // Prepared statements rely on buffered retry/replay, so they cannot be streamed live. Run the
223
+ // buffered path and replay the already-parsed result through a buffered query_stream — no JSON
224
+ // re-serialization or re-parsing — so callers observe identical semantics to the adhoc path.
225
+ auto& io = core.io_context();
226
+ core.execute(std::move(request),
227
+ [&io, obs_rec = std::move(obs_rec), handler = std::move(handler)](
228
+ operations::query_response resp) mutable {
229
+ if (resp.ctx.ec) {
230
+ // Terminal reached before a handle exists: record the operation metric/span
231
+ // here.
232
+ obs_rec->finish(resp.ctx.ec);
233
+ return handler(make_error(resp.ctx), {});
234
+ }
235
+ auto stream = std::make_shared<core::query_stream>(
236
+ io, std::move(resp.rows), std::move(resp.meta));
237
+ stream->start([obs_rec = std::move(obs_rec),
238
+ handler = std::move(handler),
239
+ stream,
240
+ ctx = std::move(resp.ctx)](std::error_code early_error) mutable {
241
+ if (early_error) {
242
+ obs_rec->finish(early_error);
243
+ ctx.ec = early_error;
244
+ return handler(make_error(ctx), {});
245
+ }
246
+ // Transfer the recorder to the handle; it finishes the operation at the stream
247
+ // terminal. The buffered request's context travels with it, so a terminal
248
+ // error is reported with the same detail the buffered path would have given.
249
+ auto internal = std::make_shared<internal_query_stream_result>(
250
+ std::move(*stream), std::move(obs_rec), std::move(ctx));
251
+ handler({}, query_stream_result{ std::move(internal) });
252
+ });
253
+ });
254
+ return;
255
+ }
256
+
257
+ core.query_stream(std::move(request),
258
+ [obs_rec = std::move(obs_rec), handler = std::move(handler)](
259
+ core::query_stream stream, core::error_context::query ctx) mutable {
260
+ if (ctx.ec) {
261
+ obs_rec->finish(ctx.ec);
262
+ return handler(make_error(ctx), {});
263
+ }
264
+ // The context travels with the handle: a terminal error reached later is
265
+ // reported with the same statement/endpoint detail as a failure to start,
266
+ // plus whatever the trailer said.
267
+ auto internal = std::make_shared<internal_query_stream_result>(
268
+ std::move(stream), std::move(obs_rec), std::move(ctx));
269
+ handler({}, query_stream_result{ std::move(internal) });
270
+ });
271
+ }
272
+
204
273
  auto
205
274
  build_transaction_query_result(operations::query_response resp,
206
275
  std::error_code txn_ec /*defaults to 0*/)
@@ -222,7 +291,7 @@ build_transaction_query_result(operations::query_response resp,
222
291
  { query_meta_data{
223
292
  std::move(resp.meta.request_id),
224
293
  std::move(resp.meta.client_context_id),
225
- map_status(resp.meta.status),
294
+ map_query_status(resp.meta.status),
226
295
  map_warnings(resp),
227
296
  map_metrics(resp),
228
297
  map_signature(resp),
@@ -20,9 +20,27 @@
20
20
  #include "core/operations/document_query.hxx"
21
21
 
22
22
  #include <couchbase/query_options.hxx>
23
+ #include <couchbase/query_status.hxx>
24
+
25
+ #include <memory>
26
+ #include <string>
27
+
28
+ namespace couchbase::core
29
+ {
30
+ class cluster;
31
+ } // namespace couchbase::core
23
32
 
24
33
  namespace couchbase::core::impl
25
34
  {
35
+ class observability_recorder;
36
+
37
+ /**
38
+ * Maps the N1QL `status` string from a query response onto the public query_status enum. Shared by
39
+ * the buffered result builder and the streaming result handle so there is one source of truth.
40
+ */
41
+ auto
42
+ map_query_status(std::string status) -> query_status;
43
+
26
44
  auto
27
45
  build_query_request(std::string statement,
28
46
  std::optional<std::string> query_context,
@@ -32,4 +50,22 @@ build_query_request(std::string statement,
32
50
 
33
51
  auto
34
52
  build_result(operations::query_response& resp) -> query_result;
53
+
54
+ /**
55
+ * Dispatches a query as a streaming request and resolves the handler with a query_stream_result.
56
+ *
57
+ * Adhoc requests take the lazy streaming path. Prepared statements (request.adhoc == false) are
58
+ * not streamed; they fall back to the buffered query() path and their rows are replayed through an
59
+ * in-memory query_stream so callers observe identical semantics.
60
+ *
61
+ * @param obs_rec the operation's observability recorder. Its operation span is already threaded
62
+ * into request.parent_span by the caller; ownership is transferred to the resulting stream handle,
63
+ * which calls finish() once when the stream reaches its terminal (drained, errored, or cancelled),
64
+ * so the streaming path emits the same operation span + latency metric as the buffered query().
65
+ */
66
+ void
67
+ dispatch_query_stream(const core::cluster& core,
68
+ core::operations::query_request request,
69
+ std::unique_ptr<observability_recorder> obs_rec,
70
+ query_stream_handler&& handler);
35
71
  } // namespace couchbase::core::impl