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,265 @@
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
+ #pragma once
19
+
20
+ // Translates the core N1QL query request/response to and from the couchbase.query.v1 protobuf
21
+ // messages. Rows arrive across streamed QueryResponse messages and are buffered into
22
+ // query_response::rows when no callback is provided, or delivered incrementally to row_callback
23
+ // when present; the terminal message carries the metadata. Deliberately does not reuse the
24
+ // MCBP-bound encode_to/make_response (those build an HTTP body + parse a JSON reply).
25
+ //
26
+ // Query features with no couchbase2 equivalent are reported by can_encode() so the component can
27
+ // surface feature_not_available rather than silently dropping them: the `raw` passthrough map,
28
+ // use_replica, node targeting via send_to_node, and tuning values too large for the proto's
29
+ // uint32 fields.
30
+
31
+ #include "core/json_string.hxx"
32
+ #include "core/operations/document_query.hxx"
33
+ #include "core/protostellar/json_payload.hxx"
34
+ #include "core/protostellar/query_proto.hxx"
35
+
36
+ #include <couchbase/query_profile.hxx>
37
+ #include <couchbase/query_scan_consistency.hxx>
38
+
39
+ #include <chrono>
40
+ #include <cstdint>
41
+ #include <limits>
42
+ #include <optional>
43
+ #include <string>
44
+
45
+ namespace couchbase::core::protostellar::query
46
+ {
47
+ namespace v1 = ::couchbase::query::v1;
48
+
49
+ // The proto's tuning fields are uint32 while the core request holds them as uint64, so a value
50
+ // that does not fit is not encodable: casting it would ask the gateway to use the wrapped number.
51
+ [[nodiscard]] inline auto
52
+ fits_uint32(const std::optional<std::uint64_t>& value) -> bool
53
+ {
54
+ return !value.has_value() || *value <= std::numeric_limits<std::uint32_t>::max();
55
+ }
56
+
57
+ // Query request features the couchbase2 gateway schema cannot express yet. The component maps this
58
+ // to feature_not_available instead of silently ignoring the caller's intent.
59
+ [[nodiscard]] inline auto
60
+ can_encode(const operations::query_request& request) -> bool
61
+ {
62
+ return request.raw.empty() && !request.use_replica.value_or(false) &&
63
+ !request.send_to_node.has_value() && fits_uint32(request.max_parallelism) &&
64
+ fits_uint32(request.pipeline_batch) && fits_uint32(request.pipeline_cap) &&
65
+ fits_uint32(request.scan_cap);
66
+ }
67
+
68
+ // Split the SDK query_context ("default:`bucket`.`scope`") into the proto's bucket_name/scope_name.
69
+ // Any pair of backtick-delimited identifiers is accepted; a value that does not parse leaves both
70
+ // unset (the statement is then expected to be fully qualified).
71
+ inline void
72
+ apply_query_context(const std::string& query_context, v1::QueryRequest& proto)
73
+ {
74
+ std::string bucket;
75
+ std::string scope;
76
+ std::string* current = &bucket;
77
+ bool inside = false;
78
+ int identifiers = 0;
79
+ for (const char c : query_context) {
80
+ if (c == '`') {
81
+ if (inside) { // closing backtick ends an identifier
82
+ ++identifiers;
83
+ if (identifiers == 1) {
84
+ current = &scope;
85
+ }
86
+ }
87
+ inside = !inside;
88
+ continue;
89
+ }
90
+ if (inside) {
91
+ current->push_back(c);
92
+ }
93
+ }
94
+ // A well-formed context is exactly two balanced backtick-delimited identifiers
95
+ // (`bucket`.`scope`). Anything else -- unbalanced, too few, or too many -- leaves both unset
96
+ // rather than routing on a half- or mis-parsed context.
97
+ if (!inside && identifiers == 2 && !bucket.empty() && !scope.empty()) {
98
+ proto.set_bucket_name(bucket);
99
+ proto.set_scope_name(scope);
100
+ }
101
+ }
102
+
103
+ inline auto
104
+ encode(const operations::query_request& request) -> v1::QueryRequest
105
+ {
106
+ v1::QueryRequest proto;
107
+ proto.set_statement(request.statement);
108
+ if (request.client_context_id.has_value()) {
109
+ proto.set_client_context_id(*request.client_context_id);
110
+ }
111
+ if (request.query_context.has_value()) {
112
+ apply_query_context(*request.query_context, proto);
113
+ }
114
+ proto.set_read_only(request.readonly);
115
+ proto.set_flex_index(request.flex_index);
116
+ proto.set_preserve_expiry(request.preserve_expiry);
117
+ // adhoc=false means "use a prepared statement" on the MCBP path; the gateway prepares/caches on
118
+ // its side, so we only signal intent.
119
+ if (!request.adhoc) {
120
+ proto.set_prepared(true);
121
+ }
122
+
123
+ if (request.scan_consistency.has_value()) {
124
+ switch (*request.scan_consistency) {
125
+ case query_scan_consistency::not_bounded:
126
+ proto.set_scan_consistency(v1::QueryRequest_ScanConsistency_SCAN_CONSISTENCY_NOT_BOUNDED);
127
+ break;
128
+ case query_scan_consistency::request_plus:
129
+ proto.set_scan_consistency(v1::QueryRequest_ScanConsistency_SCAN_CONSISTENCY_REQUEST_PLUS);
130
+ break;
131
+ }
132
+ }
133
+ // A non-empty mutation_state carries at_plus scan vectors; the gateway takes them as
134
+ // consistent_with mutation tokens.
135
+ for (const auto& token : request.mutation_state) {
136
+ auto* proto_token = proto.add_consistent_with();
137
+ proto_token->set_bucket_name(token.bucket_name());
138
+ proto_token->set_vbucket_id(token.partition_id());
139
+ proto_token->set_vbucket_uuid(token.partition_uuid());
140
+ proto_token->set_seq_no(token.sequence_number());
141
+ }
142
+
143
+ if (request.profile.has_value()) {
144
+ switch (*request.profile) {
145
+ case query_profile::off:
146
+ proto.set_profile_mode(v1::QueryRequest_ProfileMode_PROFILE_MODE_OFF);
147
+ break;
148
+ case query_profile::phases:
149
+ proto.set_profile_mode(v1::QueryRequest_ProfileMode_PROFILE_MODE_PHASES);
150
+ break;
151
+ case query_profile::timings:
152
+ proto.set_profile_mode(v1::QueryRequest_ProfileMode_PROFILE_MODE_TIMINGS);
153
+ break;
154
+ }
155
+ }
156
+
157
+ for (const auto& parameter : request.positional_parameters) {
158
+ proto.add_positional_parameters(json_payload(parameter));
159
+ }
160
+ for (const auto& [name, value] : request.named_parameters) {
161
+ (*proto.mutable_named_parameters())[name] = json_payload(value);
162
+ }
163
+
164
+ // Tuning options: the SDK's `metrics` flag defaults to off, so disable_metrics is its inverse.
165
+ auto* tuning = proto.mutable_tuning_options();
166
+ tuning->set_disable_metrics(!request.metrics);
167
+ if (request.max_parallelism.has_value()) {
168
+ tuning->set_max_parallelism(static_cast<std::uint32_t>(*request.max_parallelism));
169
+ }
170
+ if (request.pipeline_batch.has_value()) {
171
+ tuning->set_pipeline_batch(static_cast<std::uint32_t>(*request.pipeline_batch));
172
+ }
173
+ if (request.pipeline_cap.has_value()) {
174
+ tuning->set_pipeline_cap(static_cast<std::uint32_t>(*request.pipeline_cap));
175
+ }
176
+ if (request.scan_cap.has_value()) {
177
+ tuning->set_scan_cap(static_cast<std::uint32_t>(*request.scan_cap));
178
+ }
179
+ if (request.scan_wait.has_value()) {
180
+ const auto secs = std::chrono::duration_cast<std::chrono::seconds>(*request.scan_wait);
181
+ const auto nanos =
182
+ std::chrono::duration_cast<std::chrono::nanoseconds>(*request.scan_wait - secs);
183
+ auto* scan_wait = tuning->mutable_scan_wait();
184
+ scan_wait->set_seconds(secs.count());
185
+ scan_wait->set_nanos(static_cast<std::int32_t>(nanos.count()));
186
+ }
187
+
188
+ return proto;
189
+ }
190
+
191
+ // google.protobuf.Duration -> nanoseconds.
192
+ [[nodiscard]] inline auto
193
+ to_nanoseconds(const google::protobuf::Duration& duration) -> std::chrono::nanoseconds
194
+ {
195
+ return std::chrono::seconds{ duration.seconds() } + std::chrono::nanoseconds{ duration.nanos() };
196
+ }
197
+
198
+ [[nodiscard]] inline auto
199
+ status_to_string(v1::QueryResponse_MetaData_Status status) -> std::string
200
+ {
201
+ switch (status) {
202
+ case v1::QueryResponse_MetaData_Status_STATUS_RUNNING:
203
+ return "running";
204
+ case v1::QueryResponse_MetaData_Status_STATUS_SUCCESS:
205
+ return "success";
206
+ case v1::QueryResponse_MetaData_Status_STATUS_ERRORS:
207
+ return "errors";
208
+ case v1::QueryResponse_MetaData_Status_STATUS_COMPLETED:
209
+ return "completed";
210
+ case v1::QueryResponse_MetaData_Status_STATUS_STOPPED:
211
+ return "stopped";
212
+ case v1::QueryResponse_MetaData_Status_STATUS_TIMEOUT:
213
+ return "timeout";
214
+ case v1::QueryResponse_MetaData_Status_STATUS_CLOSED:
215
+ return "closed";
216
+ case v1::QueryResponse_MetaData_Status_STATUS_FATAL:
217
+ return "fatal";
218
+ case v1::QueryResponse_MetaData_Status_STATUS_ABORTED:
219
+ return "aborted";
220
+ default:
221
+ return "unknown";
222
+ }
223
+ }
224
+
225
+ // Fill a query_meta_data from the terminal QueryResponse.MetaData message.
226
+ inline void
227
+ decode_meta_data(const v1::QueryResponse_MetaData& proto,
228
+ operations::query_response::query_meta_data& meta)
229
+ {
230
+ meta.request_id = proto.request_id();
231
+ meta.client_context_id = proto.client_context_id();
232
+ meta.status = status_to_string(proto.status());
233
+ if (!proto.signature().empty()) {
234
+ meta.signature = proto.signature();
235
+ }
236
+ if (!proto.profile().empty()) {
237
+ meta.profile = proto.profile();
238
+ }
239
+ if (proto.has_metrics()) {
240
+ const auto& m = proto.metrics();
241
+ operations::query_response::query_metrics metrics;
242
+ metrics.elapsed_time = to_nanoseconds(m.elapsed_time());
243
+ metrics.execution_time = to_nanoseconds(m.execution_time());
244
+ metrics.result_count = m.result_count();
245
+ metrics.result_size = m.result_size();
246
+ metrics.sort_count = m.sort_count();
247
+ metrics.mutation_count = m.mutation_count();
248
+ metrics.error_count = m.error_count();
249
+ metrics.warning_count = m.warning_count();
250
+ meta.metrics = metrics;
251
+ }
252
+ if (proto.warnings_size() > 0) {
253
+ std::vector<operations::query_response::query_problem> warnings;
254
+ warnings.reserve(static_cast<std::size_t>(proto.warnings_size()));
255
+ for (const auto& w : proto.warnings()) {
256
+ operations::query_response::query_problem problem;
257
+ problem.code = w.code();
258
+ problem.message = w.message();
259
+ warnings.push_back(std::move(problem));
260
+ }
261
+ meta.warnings = std::move(warnings);
262
+ }
263
+ }
264
+
265
+ } // namespace couchbase::core::protostellar::query
@@ -0,0 +1,291 @@
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
+ #pragma once
19
+
20
+ // Translates core query index management requests to and from couchbase.admin.query.v1 (unary
21
+ // admin RPCs). The proto IndexType / IndexState enums have no `unknown` sentinel; they map to the
22
+ // lowercase strings the rest of the SDK uses.
23
+ //
24
+ // The gateway builds the N1QL statement from the request rather than taking one, so the encode
25
+ // side owns everything the statement's shape depends on: which RPC a primary index goes to, and
26
+ // how an index key is escaped.
27
+
28
+ #include "core/operations/management/query_index_build_deferred.hxx"
29
+ #include "core/operations/management/query_index_create.hxx"
30
+ #include "core/operations/management/query_index_drop.hxx"
31
+ #include "core/operations/management/query_index_get_all.hxx"
32
+ #include "couchbase/management/query_index.hxx"
33
+
34
+ #include <couchbase/admin/query/v1/query.pb.h>
35
+
36
+ #include <cstddef>
37
+ #include <string>
38
+
39
+ namespace couchbase::core::protostellar::query_index_admin
40
+ {
41
+ namespace v1 = ::couchbase::admin::query::v1;
42
+ namespace om = ::couchbase::core::operations::management;
43
+
44
+ // Whether the key is already one complete escaped identifier: an opening backtick, a body in which
45
+ // every backslash escapes the character after it and every backtick is escaped or doubled, and the
46
+ // closing backtick at the very end of the key.
47
+ //
48
+ // Ending exactly at the end is the whole question. A key whose identifier closes early -- "`a`,`b`"
49
+ // -- leaves the remainder as loose statement text, and a key ending in a lone backslash -- "`a\" --
50
+ // escapes its own closing backtick and swallows what follows it.
51
+ [[nodiscard]] inline auto
52
+ is_escaped_identifier(const std::string& key) -> bool
53
+ {
54
+ if (key.size() < 2 || key.front() != '`' || key.back() != '`') {
55
+ return false;
56
+ }
57
+ const auto last = key.size() - 1;
58
+ for (std::size_t i = 1; i < last;) {
59
+ if (key[i] == '\\') {
60
+ if (i + 1 >= last) {
61
+ return false;
62
+ }
63
+ i += 2;
64
+ continue;
65
+ }
66
+ if (key[i] == '`') {
67
+ if (i + 1 < last && key[i + 1] == '`') {
68
+ i += 2;
69
+ continue;
70
+ }
71
+ return false;
72
+ }
73
+ i += 1;
74
+ }
75
+ return true;
76
+ }
77
+
78
+ // Escapes one index key into exactly one N1QL identifier token.
79
+ //
80
+ // This is the transport's only client-supplied statement text. The gateway builds the statement
81
+ // itself and joins the field list with commas verbatim (gocbcorex cbqueryx), so whatever arrives in
82
+ // `fields` is spliced between the parentheses of CREATE INDEX unchanged. A key that closed its own
83
+ // quoting would add terms to the index -- or change the statement -- rather than name a field.
84
+ //
85
+ // The escape is the one the query parser reads back: a backslash escapes the character after it
86
+ // (parser/n1ql/util.go), so a backtick and a backslash each arrive prefixed by one. Doubling the
87
+ // backtick instead would parse, but reads back as two backticks in the name rather than one, and
88
+ // leaving the backslash bare makes the parser reject the whole statement. Anything else inside the
89
+ // quotes -- spaces, commas, parentheses, newlines -- is part of the identifier and needs no escape,
90
+ // which is why "two words" is a key and not a syntax error.
91
+ //
92
+ // A key that is already one complete identifier is passed through, because that is the form
93
+ // GetAllIndexes reports keys in and the classic query path accepts. "Already" is verified rather
94
+ // than assumed: is_escaped_identifier() is what separates a caller's pre-quoted key from a key
95
+ // carrying quotes that end early.
96
+ [[nodiscard]] inline auto
97
+ encode_index_key(const std::string& key) -> std::string
98
+ {
99
+ if (is_escaped_identifier(key)) {
100
+ return key;
101
+ }
102
+ std::string escaped;
103
+ escaped.reserve(key.size() + 2);
104
+ escaped.push_back('`');
105
+ for (const auto c : key) {
106
+ if (c == '\\' || c == '`') {
107
+ escaped.push_back('\\');
108
+ }
109
+ escaped.push_back(c);
110
+ }
111
+ escaped.push_back('`');
112
+ return escaped;
113
+ }
114
+
115
+ // Copies the keyspace onto a request whose scope/collection fields are `optional string`. An empty
116
+ // name is left unset: the gateway reads an unset scope as "the whole bucket", and a present-but-
117
+ // empty one as a scope literally named "", which it rejects.
118
+ template<typename Proto>
119
+ void
120
+ apply_keyspace(const std::string& bucket_name,
121
+ const std::string& scope_name,
122
+ const std::string& collection_name,
123
+ Proto& proto)
124
+ {
125
+ proto.set_bucket_name(bucket_name);
126
+ if (!scope_name.empty()) {
127
+ proto.set_scope_name(scope_name);
128
+ }
129
+ if (!collection_name.empty()) {
130
+ proto.set_collection_name(collection_name);
131
+ }
132
+ }
133
+
134
+ // couchbase2 CreateIndexRequest has no condition field, so a secondary index with a WHERE clause
135
+ // cannot be expressed at all -- encoding one would create an index over the whole collection under
136
+ // the name the caller asked for. A primary index has no condition to lose.
137
+ [[nodiscard]] inline auto
138
+ can_encode(const om::query_index_create_request& request) -> bool
139
+ {
140
+ return request.is_primary || !request.condition.has_value();
141
+ }
142
+
143
+ [[nodiscard]] inline auto
144
+ encode_get_all(const om::query_index_get_all_request& request) -> v1::GetAllIndexesRequest
145
+ {
146
+ v1::GetAllIndexesRequest proto;
147
+ apply_keyspace(request.bucket_name, request.scope_name, request.collection_name, proto);
148
+ return proto;
149
+ }
150
+
151
+ [[nodiscard]] inline auto
152
+ encode_create_primary(const om::query_index_create_request& request)
153
+ -> v1::CreatePrimaryIndexRequest
154
+ {
155
+ v1::CreatePrimaryIndexRequest proto;
156
+ apply_keyspace(request.bucket_name, request.scope_name, request.collection_name, proto);
157
+ // An unset name asks the server for its own default (#primary); an empty one is not a name.
158
+ if (!request.index_name.empty()) {
159
+ proto.set_name(request.index_name);
160
+ }
161
+ if (request.num_replicas.has_value()) {
162
+ proto.set_num_replicas(*request.num_replicas);
163
+ }
164
+ if (request.deferred.has_value()) {
165
+ proto.set_deferred(*request.deferred);
166
+ }
167
+ proto.set_ignore_if_exists(request.ignore_if_exists);
168
+ return proto;
169
+ }
170
+
171
+ [[nodiscard]] inline auto
172
+ encode_create(const om::query_index_create_request& request) -> v1::CreateIndexRequest
173
+ {
174
+ v1::CreateIndexRequest proto;
175
+ apply_keyspace(request.bucket_name, request.scope_name, request.collection_name, proto);
176
+ proto.set_name(request.index_name);
177
+ for (const auto& key : request.keys) {
178
+ proto.add_fields(encode_index_key(key));
179
+ }
180
+ if (request.num_replicas.has_value()) {
181
+ proto.set_num_replicas(*request.num_replicas);
182
+ }
183
+ if (request.deferred.has_value()) {
184
+ proto.set_deferred(*request.deferred);
185
+ }
186
+ proto.set_ignore_if_exists(request.ignore_if_exists);
187
+ return proto;
188
+ }
189
+
190
+ [[nodiscard]] inline auto
191
+ encode_drop_primary(const om::query_index_drop_request& request) -> v1::DropPrimaryIndexRequest
192
+ {
193
+ v1::DropPrimaryIndexRequest proto;
194
+ apply_keyspace(request.bucket_name, request.scope_name, request.collection_name, proto);
195
+ if (!request.index_name.empty()) {
196
+ proto.set_name(request.index_name);
197
+ }
198
+ proto.set_ignore_if_missing(request.ignore_if_does_not_exist);
199
+ return proto;
200
+ }
201
+
202
+ [[nodiscard]] inline auto
203
+ encode_drop(const om::query_index_drop_request& request) -> v1::DropIndexRequest
204
+ {
205
+ v1::DropIndexRequest proto;
206
+ apply_keyspace(request.bucket_name, request.scope_name, request.collection_name, proto);
207
+ proto.set_name(request.index_name);
208
+ proto.set_ignore_if_missing(request.ignore_if_does_not_exist);
209
+ return proto;
210
+ }
211
+
212
+ [[nodiscard]] inline auto
213
+ encode_build_deferred(const om::query_index_build_deferred_request& request)
214
+ -> v1::BuildDeferredIndexesRequest
215
+ {
216
+ v1::BuildDeferredIndexesRequest proto;
217
+ apply_keyspace(request.bucket_name,
218
+ request.scope_name.value_or(std::string{}),
219
+ request.collection_name.value_or(std::string{}),
220
+ proto);
221
+ return proto;
222
+ }
223
+
224
+ [[nodiscard]] inline auto
225
+ index_type_to_string(v1::IndexType type) -> std::string
226
+ {
227
+ switch (type) {
228
+ case v1::INDEX_TYPE_VIEW:
229
+ return "view";
230
+ case v1::INDEX_TYPE_GSI:
231
+ return "gsi";
232
+ default:
233
+ return "unknown";
234
+ }
235
+ }
236
+
237
+ [[nodiscard]] inline auto
238
+ index_state_to_string(v1::IndexState state) -> std::string
239
+ {
240
+ switch (state) {
241
+ case v1::INDEX_STATE_DEFERRED:
242
+ return "deferred";
243
+ case v1::INDEX_STATE_BUILDING:
244
+ return "building";
245
+ case v1::INDEX_STATE_PENDING:
246
+ return "pending";
247
+ case v1::INDEX_STATE_ONLINE:
248
+ return "online";
249
+ case v1::INDEX_STATE_OFFLINE:
250
+ return "offline";
251
+ case v1::INDEX_STATE_ABRIDGED:
252
+ return "abridged";
253
+ case v1::INDEX_STATE_SCHEDULED:
254
+ return "scheduled";
255
+ default:
256
+ return "unknown";
257
+ }
258
+ }
259
+
260
+ [[nodiscard]] inline auto
261
+ decode_index(const v1::GetAllIndexesResponse_Index& proto) -> couchbase::management::query_index
262
+ {
263
+ couchbase::management::query_index index;
264
+ index.is_primary = proto.is_primary();
265
+ index.name = proto.name();
266
+ index.type = index_type_to_string(proto.type());
267
+ index.state = index_state_to_string(proto.state());
268
+ index.bucket_name = proto.bucket_name();
269
+ if (!proto.scope_name().empty()) {
270
+ index.scope_name = proto.scope_name();
271
+ }
272
+ if (!proto.collection_name().empty()) {
273
+ index.collection_name = proto.collection_name();
274
+ }
275
+ for (const auto& field : proto.fields()) {
276
+ index.index_key.push_back(field);
277
+ }
278
+ // Presence, not emptiness: condition and partition are `optional string`, so an index that has
279
+ // no WHERE clause is a different answer from one whose clause the server reports as empty.
280
+ // scope_name and collection_name above carry no presence, so there an empty name is the only
281
+ // form "not collection-qualified" can arrive in.
282
+ if (proto.has_condition()) {
283
+ index.condition = proto.condition();
284
+ }
285
+ if (proto.has_partition()) {
286
+ index.partition = proto.partition();
287
+ }
288
+ return index;
289
+ }
290
+
291
+ } // namespace couchbase::core::protostellar::query_index_admin
@@ -0,0 +1,73 @@
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
+ #pragma once
19
+
20
+ // The one place the generated couchbase.query.v1 headers are included. Include this instead of
21
+ // <couchbase/query/v1/query.pb.h> or <couchbase/query/v1/query.grpc.pb.h>.
22
+ //
23
+ // protobuf emits a class-scoped alias for every enum value ("static constexpr Status STATUS_TIMEOUT
24
+ // = ..."), and the Windows SDK spells much of that same STATUS_* namespace as object-like macros:
25
+ // <winnt.h> defines STATUS_TIMEOUT as ((DWORD)0x00000102L), and asio and gRPC reach <winnt.h>
26
+ // transitively. On MSVC the alias then expands into a parenthesised constant and the generated
27
+ // header does not parse. No other compiler is affected, so the Linux and macOS legs cannot catch
28
+ // it.
29
+ //
30
+ // The whole QueryResponse.MetaData.Status family is suppressed, not just the one name that collides
31
+ // today: <ntstatus.h> covers far more of the STATUS_* namespace than <winnt.h> does (STATUS_SUCCESS
32
+ // among it) and any dependency may start pulling it in. push_macro/pop_macro keeps the suppression
33
+ // scoped to the includes below, so a translation unit that includes this header does not silently
34
+ // lose a macro it uses elsewhere -- which a bare #undef in a header would do. Pushing and popping a
35
+ // macro that is not defined is a no-op, so this needs no _MSC_VER guard.
36
+ //
37
+ // When the schema pin in cmake/Protostellar.cmake moves, bin/check-proto-macro-collisions reports
38
+ // generated aliases that collide with a Windows macro, including families other than this one.
39
+
40
+ #pragma push_macro("STATUS_ABORTED")
41
+ #pragma push_macro("STATUS_CLOSED")
42
+ #pragma push_macro("STATUS_COMPLETED")
43
+ #pragma push_macro("STATUS_ERRORS")
44
+ #pragma push_macro("STATUS_FATAL")
45
+ #pragma push_macro("STATUS_RUNNING")
46
+ #pragma push_macro("STATUS_STOPPED")
47
+ #pragma push_macro("STATUS_SUCCESS")
48
+ #pragma push_macro("STATUS_TIMEOUT")
49
+ #pragma push_macro("STATUS_UNKNOWN")
50
+ #undef STATUS_ABORTED
51
+ #undef STATUS_CLOSED
52
+ #undef STATUS_COMPLETED
53
+ #undef STATUS_ERRORS
54
+ #undef STATUS_FATAL
55
+ #undef STATUS_RUNNING
56
+ #undef STATUS_STOPPED
57
+ #undef STATUS_SUCCESS
58
+ #undef STATUS_TIMEOUT
59
+ #undef STATUS_UNKNOWN
60
+
61
+ #include <couchbase/query/v1/query.grpc.pb.h>
62
+ #include <couchbase/query/v1/query.pb.h>
63
+
64
+ #pragma pop_macro("STATUS_UNKNOWN")
65
+ #pragma pop_macro("STATUS_TIMEOUT")
66
+ #pragma pop_macro("STATUS_SUCCESS")
67
+ #pragma pop_macro("STATUS_STOPPED")
68
+ #pragma pop_macro("STATUS_RUNNING")
69
+ #pragma pop_macro("STATUS_FATAL")
70
+ #pragma pop_macro("STATUS_ERRORS")
71
+ #pragma pop_macro("STATUS_COMPLETED")
72
+ #pragma pop_macro("STATUS_CLOSED")
73
+ #pragma pop_macro("STATUS_ABORTED")