couchbase 3.8.2 → 3.9.0

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 +130 -21
  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 +10 -3
  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 +1554 -398
  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 +59 -5
  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 +3 -29
  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 +32 -0
  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,244 @@
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 FTS search request/response to and from couchbase.search.v1. Hits arrive
21
+ // across streamed SearchQueryResponse messages and are buffered into search_response::rows; the
22
+ // terminal message carries the metadata.
23
+ //
24
+ // The couchbase2 SearchQueryRequest models the FTS query as a structured `Query` oneof of 21 types,
25
+ // whereas the core request carries an opaque pre-serialized JSON `query`. This converter translates
26
+ // the trivial forms -- query_string (optionally boosted), match_all and match_none -- and reports
27
+ // every other shape as unmappable so the component surfaces feature_not_available. Structured
28
+ // facets, structured sort specs, vector search, mutation-token consistency, the `raw`
29
+ // passthrough, and score fusion (rrf/rsf) have no couchbase2 home and are likewise gated;
30
+ // `scoring(none())` predates fusion and maps onto the protocol's existing disable_scoring field, so
31
+ // it is not gated. Translating the remaining eighteen query arms is a follow-up; the gate is what
32
+ // keeps an untranslated one from being dropped in silence in the meantime.
33
+
34
+ #include "core/operations/document_search.hxx"
35
+ #include "core/utils/json.hxx"
36
+
37
+ #include <couchbase/search/v1/search.pb.h>
38
+
39
+ // core/utils/json.hxx only forward-declares tao::json::value; this header instantiates one and
40
+ // calls its members, so it needs the full definition.
41
+ #include <tao/json/value.hpp>
42
+
43
+ #include <chrono>
44
+ #include <cstdint>
45
+ #include <optional>
46
+ #include <string>
47
+ #include <vector>
48
+
49
+ namespace couchbase::core::protostellar::search
50
+ {
51
+ namespace v1 = ::couchbase::search::v1;
52
+
53
+ // Coarse, cheap gate for request features with no couchbase2 mapping. Query-shape support is
54
+ // decided in encode() (which must parse the query JSON).
55
+ [[nodiscard]] inline auto
56
+ can_encode(const operations::search_request& request) -> bool
57
+ {
58
+ return request.raw.empty() && request.facets.empty() && request.sort_specs.empty() &&
59
+ request.mutation_state.empty() && !request.vector_search.has_value() &&
60
+ !request.vector_query_combination.has_value() && !request.row_callback.has_value() &&
61
+ !couchbase::core::is_score_fusion(request.scoring);
62
+ }
63
+
64
+ // True when request.query does not parse as JSON at all, as opposed to parsing into a shape this
65
+ // converter does not translate. The component maps the two to different errors: a query the caller
66
+ // failed to serialize is their own invalid_argument, not a gap in couchbase2 support.
67
+ [[nodiscard]] inline auto
68
+ query_is_malformed(const operations::search_request& request) -> bool
69
+ {
70
+ try {
71
+ static_cast<void>(utils::json::parse(request.query));
72
+ } catch (...) {
73
+ return true;
74
+ }
75
+ return false;
76
+ }
77
+
78
+ // Translate the parsed core query JSON into the structured Query oneof, for the trivial forms only.
79
+ // Returns false, leaving proto.query unset, for every shape this converter does not translate.
80
+ [[nodiscard]] inline auto
81
+ apply_query(const tao::json::value& parsed, v1::SearchQueryRequest& proto) -> bool
82
+ {
83
+ if (!parsed.is_object()) {
84
+ return false;
85
+ }
86
+ // A boost is serialized beside the query key rather than inside it: query_string("foo").boost(2)
87
+ // encodes as {"query":"foo","boost":2}. Rejecting every two-key object would therefore make an
88
+ // ordinary boosted query unroutable, so a boost is read as a modifier of the recognized key.
89
+ // Whether it can actually be carried depends on the arm, and is decided below. Any other sibling
90
+ // (an analyzer, a field) would be lost in translation, so a wider object is reported as
91
+ // unmappable and the component surfaces feature_not_available.
92
+ const auto* boost = parsed.find("boost");
93
+ if (parsed.get_object().size() > (boost == nullptr ? 1U : 2U)) {
94
+ return false;
95
+ }
96
+ const auto* match_all = parsed.find("match_all");
97
+ const auto* match_none = parsed.find("match_none");
98
+ if (match_all != nullptr || match_none != nullptr) {
99
+ // MatchAllQuery and MatchNoneQuery are empty messages, so a boost on either has nowhere to go.
100
+ // Refusing the request keeps it from being run at a weight the caller did not ask for.
101
+ if (boost != nullptr) {
102
+ return false;
103
+ }
104
+ if (match_all != nullptr) {
105
+ proto.mutable_query()->mutable_match_all_query();
106
+ } else {
107
+ proto.mutable_query()->mutable_match_none_query();
108
+ }
109
+ return true;
110
+ }
111
+ if (const auto* q = parsed.find("query"); q != nullptr && q->is_string()) {
112
+ auto* query_string = proto.mutable_query()->mutable_query_string_query();
113
+ query_string->set_query_string(q->get_string());
114
+ if (boost != nullptr) {
115
+ if (!boost->is_number()) {
116
+ return false;
117
+ }
118
+ query_string->set_boost(static_cast<float>(boost->as<double>()));
119
+ }
120
+ return true;
121
+ }
122
+ return false;
123
+ }
124
+
125
+ // Encode the request; returns nullopt for a gated feature, an untranslated query shape, or a query
126
+ // that is not JSON. The component separates the last case with query_is_malformed().
127
+ [[nodiscard]] inline auto
128
+ encode(const operations::search_request& request) -> std::optional<v1::SearchQueryRequest>
129
+ {
130
+ if (!can_encode(request)) {
131
+ return std::nullopt;
132
+ }
133
+ v1::SearchQueryRequest proto;
134
+ proto.set_index_name(request.index_name);
135
+ if (request.bucket_name.has_value()) {
136
+ proto.set_bucket_name(*request.bucket_name);
137
+ }
138
+ if (request.scope_name.has_value()) {
139
+ proto.set_scope_name(*request.scope_name);
140
+ }
141
+ tao::json::value parsed;
142
+ try {
143
+ parsed = utils::json::parse(request.query);
144
+ } catch (...) {
145
+ return std::nullopt;
146
+ }
147
+ if (!apply_query(parsed, proto)) {
148
+ return std::nullopt;
149
+ }
150
+ if (request.limit.has_value()) {
151
+ proto.set_limit(*request.limit);
152
+ }
153
+ if (request.skip.has_value()) {
154
+ proto.set_skip(*request.skip);
155
+ }
156
+ if (request.explain.value_or(false)) {
157
+ proto.set_include_explanation(true);
158
+ }
159
+ proto.set_disable_scoring(
160
+ request.disable_scoring ||
161
+ std::holds_alternative<couchbase::core::search_scoring_none>(request.scoring));
162
+ proto.set_include_locations(request.include_locations);
163
+ proto.set_scan_consistency(v1::SearchQueryRequest_ScanConsistency_SCAN_CONSISTENCY_NOT_BOUNDED);
164
+ if (request.highlight_style.has_value()) {
165
+ proto.set_highlight_style(*request.highlight_style == search_highlight_style::ansi
166
+ ? v1::SearchQueryRequest_HighlightStyle_HIGHLIGHT_STYLE_ANSI
167
+ : v1::SearchQueryRequest_HighlightStyle_HIGHLIGHT_STYLE_HTML);
168
+ }
169
+ for (const auto& field : request.highlight_fields) {
170
+ proto.add_highlight_fields(field);
171
+ }
172
+ for (const auto& field : request.fields) {
173
+ proto.add_fields(field);
174
+ }
175
+ for (const auto& collection : request.collections) {
176
+ proto.add_collections(collection);
177
+ }
178
+ return proto;
179
+ }
180
+
181
+ // Append the hits from one streamed message onto the buffered response and, if present, decode the
182
+ // terminal metadata. Structured facets are gated by can_encode(), so a response cannot carry any.
183
+ inline void
184
+ decode(const v1::SearchQueryResponse& message, operations::search_response& response)
185
+ {
186
+ for (const auto& hit : message.hits()) {
187
+ operations::search_response::search_row row;
188
+ row.index = hit.index();
189
+ row.id = hit.id();
190
+ row.score = hit.score();
191
+ row.explanation = hit.explanation();
192
+ for (const auto& [field, fragment] : hit.fragments()) {
193
+ row.fragments[field] =
194
+ std::vector<std::string>{ fragment.content().begin(), fragment.content().end() };
195
+ }
196
+ // The proto keys each requested field to its value as raw JSON, whereas the core row carries
197
+ // the whole set as one JSON object, so the object is reassembled here.
198
+ if (!hit.fields().empty()) {
199
+ tao::json::value fields = tao::json::empty_object;
200
+ for (const auto& [name, value] : hit.fields()) {
201
+ try {
202
+ fields[name] = utils::json::parse(value);
203
+ } catch (...) {
204
+ // decode() runs on the io_context out of a stream callback, where an escaping exception
205
+ // would take down the loop. A value that is not JSON is kept verbatim as a string so the
206
+ // field still reaches the caller.
207
+ fields[name] = value;
208
+ }
209
+ }
210
+ row.fields = utils::json::generate(fields);
211
+ }
212
+ for (const auto& location : hit.locations()) {
213
+ operations::search_response::search_location out;
214
+ out.field = location.field();
215
+ out.term = location.term();
216
+ out.position = location.position();
217
+ out.start_offset = location.start();
218
+ out.end_offset = location.end();
219
+ if (location.array_positions_size() > 0) {
220
+ out.array_positions = std::vector<std::uint64_t>{ location.array_positions().begin(),
221
+ location.array_positions().end() };
222
+ }
223
+ row.locations.push_back(std::move(out));
224
+ }
225
+ response.rows.push_back(std::move(row));
226
+ }
227
+ if (message.has_meta_data()) {
228
+ const auto& meta = message.meta_data();
229
+ if (meta.has_metrics()) {
230
+ const auto& m = meta.metrics();
231
+ response.meta.metrics.took = std::chrono::seconds{ m.execution_time().seconds() } +
232
+ std::chrono::nanoseconds{ m.execution_time().nanos() };
233
+ response.meta.metrics.total_rows = m.total_rows();
234
+ response.meta.metrics.max_score = m.max_score();
235
+ response.meta.metrics.success_partition_count = m.success_partition_count();
236
+ response.meta.metrics.error_partition_count = m.error_partition_count();
237
+ }
238
+ for (const auto& [location, msg] : meta.errors()) {
239
+ response.meta.errors.try_emplace(location, msg);
240
+ }
241
+ }
242
+ }
243
+
244
+ } // namespace couchbase::core::protostellar::search
@@ -0,0 +1,156 @@
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 FTS index settings to and from couchbase.admin.search.v1. The one non-trivial
21
+ // bit: core stores params/plan_params/source_params as single JSON-object strings, while the proto
22
+ // Index uses map<string,bytes> keyed by the object's top-level members (each value a raw-JSON
23
+ // blob). fill_params/params_to_json round-trip between the two representations.
24
+ //
25
+ // Every conversion that can lose a member reports failure instead. A definition that cannot be
26
+ // represented must not be truncated in silence: the caller edits what get_index returned and
27
+ // upserts it back, so a dropped member deletes part of the index definition while the call reports
28
+ // success.
29
+
30
+ #include "core/management/search_index.hxx"
31
+ #include "core/utils/json.hxx"
32
+
33
+ #include <tao/json/value.hpp>
34
+
35
+ #include <couchbase/admin/search/v1/search.pb.h>
36
+
37
+ #include <google/protobuf/map.h>
38
+
39
+ #include <optional>
40
+ #include <string>
41
+
42
+ namespace couchbase::core::protostellar::search_index_admin
43
+ {
44
+ namespace v1 = ::couchbase::admin::search::v1;
45
+
46
+ // Explode a JSON-object string into the proto map: one entry per top-level member, value = the
47
+ // member's raw JSON. An empty input is the "unset" convention and contributes nothing. Anything
48
+ // that is not a JSON object has no representation in the map and is refused.
49
+ [[nodiscard]] inline auto
50
+ fill_params(const std::string& json, ::google::protobuf::Map<std::string, std::string>* target)
51
+ -> bool
52
+ {
53
+ if (json.empty()) {
54
+ return true;
55
+ }
56
+ tao::json::value parsed;
57
+ try {
58
+ parsed = utils::json::parse(json);
59
+ } catch (...) {
60
+ return false;
61
+ }
62
+ if (!parsed.is_object()) {
63
+ return false;
64
+ }
65
+ for (const auto& [key, value] : parsed.get_object()) {
66
+ (*target)[key] = utils::json::generate(value);
67
+ }
68
+ return true;
69
+ }
70
+
71
+ // Rebuild a JSON-object string from the proto map (inverse of fill_params). Empty map -> empty
72
+ // string so the core struct keeps its "unset" convention. A member whose bytes are not JSON cannot
73
+ // be placed in the object, and dropping it would hand back a definition short of what the server
74
+ // holds, so the whole conversion fails.
75
+ [[nodiscard]] inline auto
76
+ params_to_json(const ::google::protobuf::Map<std::string, std::string>& source)
77
+ -> std::optional<std::string>
78
+ {
79
+ if (source.empty()) {
80
+ return std::string{};
81
+ }
82
+ tao::json::value object = tao::json::empty_object;
83
+ for (const auto& [key, value] : source) {
84
+ try {
85
+ object[key] = utils::json::parse(value);
86
+ } catch (...) {
87
+ return {};
88
+ }
89
+ }
90
+ return utils::json::generate(object);
91
+ }
92
+
93
+ // The fields shared by CreateIndexRequest and Index. The two messages carry the same index
94
+ // definition under the same field names, but they are unrelated proto types and neither derives
95
+ // from the other, so the assignments are written once against whichever is passed.
96
+ template<typename Proto>
97
+ [[nodiscard]] auto
98
+ apply_index_fields(const management::search::index& index, Proto& proto) -> bool
99
+ {
100
+ proto.set_name(index.name);
101
+ proto.set_type(index.type);
102
+ if (!index.source_name.empty()) {
103
+ proto.set_source_name(index.source_name);
104
+ }
105
+ if (!index.source_type.empty()) {
106
+ proto.set_source_type(index.source_type);
107
+ }
108
+ if (!index.source_uuid.empty()) {
109
+ proto.set_source_uuid(index.source_uuid);
110
+ }
111
+ return fill_params(index.params_json, proto.mutable_params()) &&
112
+ fill_params(index.plan_params_json, proto.mutable_plan_params()) &&
113
+ fill_params(index.source_params_json, proto.mutable_source_params());
114
+ }
115
+
116
+ // Encode a core index into a CreateIndexRequest. A create carries no uuid: an upsert that supplies
117
+ // one is an update and goes to UpdateIndex instead.
118
+ [[nodiscard]] inline auto
119
+ apply_index(const management::search::index& index, v1::CreateIndexRequest& proto) -> bool
120
+ {
121
+ return apply_index_fields(index, proto);
122
+ }
123
+
124
+ // Encode a core index into the Index of an UpdateIndexRequest. The uuid is what makes it an
125
+ // update: the gateway rejects the call without one, and the server matches it against the current
126
+ // definition so a concurrent update is not overwritten.
127
+ [[nodiscard]] inline auto
128
+ apply_index(const management::search::index& index, v1::Index& proto) -> bool
129
+ {
130
+ proto.set_uuid(index.uuid);
131
+ return apply_index_fields(index, proto);
132
+ }
133
+
134
+ [[nodiscard]] inline auto
135
+ decode_index(const v1::Index& proto) -> std::optional<management::search::index>
136
+ {
137
+ auto params = params_to_json(proto.params());
138
+ auto plan_params = params_to_json(proto.plan_params());
139
+ auto source_params = params_to_json(proto.source_params());
140
+ if (!params.has_value() || !plan_params.has_value() || !source_params.has_value()) {
141
+ return {};
142
+ }
143
+ management::search::index index;
144
+ index.uuid = proto.uuid();
145
+ index.name = proto.name();
146
+ index.type = proto.type();
147
+ index.source_uuid = proto.source_uuid();
148
+ index.source_name = proto.source_name();
149
+ index.source_type = proto.source_type();
150
+ index.params_json = std::move(*params);
151
+ index.plan_params_json = std::move(*plan_params);
152
+ index.source_params_json = std::move(*source_params);
153
+ return index;
154
+ }
155
+
156
+ } // namespace couchbase::core::protostellar::search_index_admin
@@ -0,0 +1,158 @@
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
+ // Views are deprecated in the core API but still routable over couchbase2; suppress the core
21
+ // deprecation attribute for this header. push/pop the macro so an including translation unit that
22
+ // already defined it keeps its state restored, rather than having it clobbered at the bottom.
23
+ #pragma push_macro("COUCHBASE_CXX_CLIENT_IGNORE_CORE_DEPRECATIONS")
24
+ #define COUCHBASE_CXX_CLIENT_IGNORE_CORE_DEPRECATIONS
25
+
26
+ // Translates the core map/reduce view request/response to and from couchbase.view.v1. Rows arrive
27
+ // across streamed ViewQueryResponse messages and are buffered into document_view_response::rows;
28
+ // the terminal message carries the metadata.
29
+ //
30
+ // The couchbase2 ViewQueryRequest has no home for the core request's `raw`, `query_string`,
31
+ // `full_set`, or streaming `row_callback` fields; can_encode() reports those so the component
32
+ // surfaces feature_not_available rather than silently dropping them. The proto `limit`/`skip` are
33
+ // uint32 while core carries uint64, so can_encode() also rejects values that would truncate.
34
+ // `client_context_id`/`timeout` likewise have no proto field but do not change results, so they are
35
+ // simply not sent.
36
+
37
+ #include "core/operations/document_view.hxx"
38
+
39
+ #include <couchbase/view/v1/view.pb.h>
40
+
41
+ #include <cstdint>
42
+ #include <limits>
43
+ #include <string>
44
+
45
+ namespace couchbase::core::protostellar::view
46
+ {
47
+ namespace v1 = ::couchbase::view::v1;
48
+
49
+ [[nodiscard]] inline auto
50
+ can_encode(const operations::document_view_request& request) -> bool
51
+ {
52
+ constexpr auto u32_max = (std::numeric_limits<std::uint32_t>::max)();
53
+ return request.raw.empty() && request.query_string.empty() && !request.full_set.value_or(false) &&
54
+ !request.row_callback.has_value() && request.limit.value_or(0) <= u32_max &&
55
+ request.skip.value_or(0) <= u32_max;
56
+ }
57
+
58
+ inline auto
59
+ encode(const operations::document_view_request& request) -> v1::ViewQueryRequest
60
+ {
61
+ v1::ViewQueryRequest proto;
62
+ proto.set_bucket_name(request.bucket_name);
63
+ proto.set_design_document_name(request.document_name);
64
+ proto.set_view_name(request.view_name);
65
+ proto.set_namespace_(request.ns == design_document_namespace::development
66
+ ? v1::ViewQueryRequest_Namespace_NAMESPACE_DEVELOPMENT
67
+ : v1::ViewQueryRequest_Namespace_NAMESPACE_PRODUCTION);
68
+
69
+ for (const auto& key : request.keys) {
70
+ proto.add_keys(key);
71
+ }
72
+ if (request.key.has_value()) {
73
+ proto.set_key(*request.key);
74
+ }
75
+ if (request.start_key.has_value()) {
76
+ proto.set_start_key(*request.start_key);
77
+ }
78
+ if (request.end_key.has_value()) {
79
+ proto.set_end_key(*request.end_key);
80
+ }
81
+ if (request.start_key_doc_id.has_value()) {
82
+ proto.set_start_key_doc_id(*request.start_key_doc_id);
83
+ }
84
+ if (request.end_key_doc_id.has_value()) {
85
+ proto.set_end_key_doc_id(*request.end_key_doc_id);
86
+ }
87
+ if (request.limit.has_value()) {
88
+ proto.set_limit(static_cast<std::uint32_t>(*request.limit));
89
+ }
90
+ if (request.skip.has_value()) {
91
+ proto.set_skip(static_cast<std::uint32_t>(*request.skip));
92
+ }
93
+ if (request.reduce.has_value()) {
94
+ proto.set_reduce(*request.reduce);
95
+ }
96
+ if (request.group.has_value()) {
97
+ proto.set_group(*request.group);
98
+ }
99
+ if (request.group_level.has_value()) {
100
+ proto.set_group_level(*request.group_level);
101
+ }
102
+ if (request.inclusive_end.has_value()) {
103
+ proto.set_inclusive_end(*request.inclusive_end);
104
+ }
105
+ proto.set_debug(request.debug);
106
+ if (request.consistency.has_value()) {
107
+ switch (*request.consistency) {
108
+ case view_scan_consistency::not_bounded:
109
+ proto.set_scan_consistency(
110
+ v1::ViewQueryRequest_ScanConsistency_SCAN_CONSISTENCY_NOT_BOUNDED);
111
+ break;
112
+ case view_scan_consistency::update_after:
113
+ proto.set_scan_consistency(
114
+ v1::ViewQueryRequest_ScanConsistency_SCAN_CONSISTENCY_UPDATE_AFTER);
115
+ break;
116
+ case view_scan_consistency::request_plus:
117
+ proto.set_scan_consistency(
118
+ v1::ViewQueryRequest_ScanConsistency_SCAN_CONSISTENCY_REQUEST_PLUS);
119
+ break;
120
+ }
121
+ }
122
+ if (request.order.has_value()) {
123
+ proto.set_order(*request.order == view_sort_order::descending
124
+ ? v1::ViewQueryRequest_Order_ORDER_DESCENDING
125
+ : v1::ViewQueryRequest_Order_ORDER_ASCENDING);
126
+ }
127
+ if (request.on_error.has_value()) {
128
+ proto.set_on_error(*request.on_error == view_on_error::stop
129
+ ? v1::ViewQueryRequest_ErrorMode_ERROR_MODE_STOP
130
+ : v1::ViewQueryRequest_ErrorMode_ERROR_MODE_CONTINUE);
131
+ }
132
+ return proto;
133
+ }
134
+
135
+ // Append the rows from one streamed message onto the buffered response.
136
+ inline void
137
+ decode_rows(const v1::ViewQueryResponse& message, operations::document_view_response& response)
138
+ {
139
+ for (const auto& row : message.rows()) {
140
+ operations::document_view_response::row out;
141
+ if (!row.id().empty()) {
142
+ out.id = row.id();
143
+ }
144
+ out.key = row.key();
145
+ out.value = row.value();
146
+ response.rows.push_back(std::move(out));
147
+ }
148
+ if (message.has_meta_data()) {
149
+ response.meta.total_rows = message.meta_data().total_rows();
150
+ if (!message.meta_data().debug().empty()) {
151
+ response.meta.debug_info = message.meta_data().debug();
152
+ }
153
+ }
154
+ }
155
+
156
+ } // namespace couchbase::core::protostellar::view
157
+
158
+ #pragma pop_macro("COUCHBASE_CXX_CLIENT_IGNORE_CORE_DEPRECATIONS")