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,600 @@
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 KV operation request/response structs to and from the couchbase.kv.v1
21
+ // protobuf messages. The response builders take an already-populated key_value_error_context (the
22
+ // component derives it from the gRPC status) and fill the value/cas/token, deliberately not
23
+ // reusing the MCBP-bound encode_to/make_response.
24
+
25
+ #include "core/document_id.hxx"
26
+ #include "core/error_context/key_value.hxx"
27
+ #include "core/logger/logger.hxx"
28
+ #include "core/operations/document_append.hxx"
29
+ #include "core/operations/document_decrement.hxx"
30
+ #include "core/operations/document_exists.hxx"
31
+ #include "core/operations/document_get.hxx"
32
+ #include "core/operations/document_get_and_lock.hxx"
33
+ #include "core/operations/document_get_and_touch.hxx"
34
+ #include "core/operations/document_get_projected.hxx"
35
+ #include "core/operations/document_increment.hxx"
36
+ #include "core/operations/document_insert.hxx"
37
+ #include "core/operations/document_prepend.hxx"
38
+ #include "core/operations/document_remove.hxx"
39
+ #include "core/operations/document_replace.hxx"
40
+ #include "core/operations/document_touch.hxx"
41
+ #include "core/operations/document_unlock.hxx"
42
+ #include "core/operations/document_upsert.hxx"
43
+ #include "core/protostellar/compression_settings.hxx"
44
+ #include "core/utils/binary.hxx"
45
+
46
+ #include <couchbase/cas.hxx>
47
+ #include <couchbase/durability_level.hxx>
48
+ #include <couchbase/error_codes.hxx>
49
+ #include <couchbase/mutation_token.hxx>
50
+
51
+ #include <couchbase/kv/v1/kv.pb.h>
52
+
53
+ #include <cstdint>
54
+ #include <optional>
55
+ #include <string>
56
+
57
+ namespace couchbase::core::protostellar::kv
58
+ {
59
+ namespace v1 = ::couchbase::kv::v1;
60
+
61
+ // Value bytes go through core::utils::to_binary / to_string so the couchbase2 path shares one
62
+ // conversion with the rest of core rather than carrying its own memcpy helpers.
63
+
64
+ template<typename Request>
65
+ void
66
+ set_location(Request& proto, const document_id& id)
67
+ {
68
+ proto.set_bucket_name(id.bucket());
69
+ proto.set_scope_name(id.scope());
70
+ proto.set_collection_name(id.collection());
71
+ proto.set_key(id.key());
72
+ }
73
+
74
+ // The expiry encoding below is dictated by the gateway, which is what translates these messages
75
+ // into MCBP and is therefore the authority on what each shape means. Line references are to
76
+ // couchbase/stellar-gateway at commit 910af15aefcc094378636972dd22875c5e485ee9, and are pinned to
77
+ // the exact file contents by blob hash so they stay checkable after the files move:
78
+ //
79
+ // kvserver.go git cat-file -p dde6353d06439fa4d8e0445f2362e8b460ff1265
80
+ // helpers.go git cat-file -p 5bd3ad7dcaf3bf2ada354ad9846cf4a87aa73a31
81
+ //
82
+ // The core request carries expiry with the memcached convention: a value of at most the 30-day
83
+ // cutoff is a relative duration in seconds; above it, it is an absolute Unix-epoch timestamp (this
84
+ // is how core/impl/expiry.cxx encodes durations >= 30 days and absolute time points).
85
+ //
86
+ // The proto oneof is not that shape. expiry_secs is *always* a duration: the gateway passes it
87
+ // through when it is <= 2592000 and otherwise re-bases it onto "now + N seconds"
88
+ // (helpers.go:48-67, secsExpiryToGocbcorex), so an already-absolute core value sent through
89
+ // expiry_secs would be read as a ~50-year duration. Absolute values therefore have to use
90
+ // expiry_time, which the gateway takes as an epoch second (helpers.go:44-46). The cutoff itself is
91
+ // relative on both sides: the gateway's own boundary is `expiry <= 2592000`.
92
+ inline constexpr std::uint32_t relative_expiry_cutoff_seconds = 60U * 60U * 24U * 30U; // 2,592,000
93
+
94
+ // An absent expiry oneof is the gateway's encoding for "preserve the document's existing expiry",
95
+ // not for "no expiry": both Upsert and Replace map a nil oneof to opts.PreserveExpiry = true
96
+ // (kvserver.go:478-484 and :580-581). "No expiry" must therefore be an explicit zero, which the
97
+ // gateway maps to never-expires (helpers.go:49-51); the classic transport serialises the same zero
98
+ // into the extras (core/protocol/cmd_upsert.cxx:82-91). Touch and GetAndTouch reject an absent
99
+ // oneof outright -- "Expiry time specification is unknown." (kvserver.go:297-303, :131-137) -- so
100
+ // the field is not optional there either. The oneof is omitted only when the caller asked to
101
+ // preserve, which for ReplaceRequest is the only available encoding: unlike UpsertRequest it has no
102
+ // preserve_expiry_on_existing field at all.
103
+ template<typename Proto>
104
+ void
105
+ set_expiry(Proto& proto, std::uint32_t expiry, bool preserve_expiry = false)
106
+ {
107
+ if (preserve_expiry) {
108
+ return;
109
+ }
110
+ if (expiry <= relative_expiry_cutoff_seconds) {
111
+ proto.set_expiry_secs(expiry);
112
+ } else {
113
+ proto.mutable_expiry_time()->set_seconds(static_cast<std::int64_t>(expiry));
114
+ }
115
+ }
116
+
117
+ // couchbase::durability_level::none means "no requirement" — the proto field is left unset.
118
+ inline auto
119
+ to_proto_durability(couchbase::durability_level level) -> std::optional<v1::DurabilityLevel>
120
+ {
121
+ switch (level) {
122
+ case couchbase::durability_level::none:
123
+ return std::nullopt;
124
+ case couchbase::durability_level::majority:
125
+ return v1::DURABILITY_LEVEL_MAJORITY;
126
+ case couchbase::durability_level::majority_and_persist_to_active:
127
+ return v1::DURABILITY_LEVEL_MAJORITY_AND_PERSIST_TO_ACTIVE;
128
+ case couchbase::durability_level::persist_to_majority:
129
+ return v1::DURABILITY_LEVEL_PERSIST_TO_MAJORITY;
130
+ }
131
+ return std::nullopt;
132
+ }
133
+
134
+ inline auto
135
+ to_core_token(const v1::MutationToken& token) -> couchbase::mutation_token
136
+ {
137
+ return couchbase::mutation_token{ token.vbucket_uuid(),
138
+ token.seq_no(),
139
+ static_cast<std::uint16_t>(token.vbucket_id()),
140
+ token.bucket_name() };
141
+ }
142
+
143
+ // Every response that carries a document body puts it in a content oneof, and the generated
144
+ // accessor for the inactive arm returns the empty-string singleton. The active arm therefore has to
145
+ // be tested before reading either one, or a compressed payload decodes to an empty value with a
146
+ // valid CAS -- indistinguishable from an empty document.
147
+ template<typename Proto>
148
+ [[nodiscard]] auto
149
+ content_is_compressed(const Proto& proto) -> bool
150
+ {
151
+ return proto.content_case() == Proto::kContentCompressed;
152
+ }
153
+
154
+ // ── Compression (RFC 77) ───────────────────────────────────────────────────────
155
+
156
+ // snappy lives in kv_converter.cxx (compiled into the client library) so <snappy.h> stays out of
157
+ // this header, which white-box tests include — they then need neither snappy's headers nor its
158
+ // symbols. maybe_compress returns the compressed bytes when compression is enabled and the value
159
+ // clears the size/ratio threshold, else std::nullopt ("store uncompressed"); snappy_uncompress
160
+ // returns std::nullopt on malformed input and on a frame declaring more than the transport's
161
+ // maximum message size, which no legitimate value can exceed.
162
+ [[nodiscard]] auto
163
+ maybe_compress(const std::vector<std::byte>& value, const compression_settings& compression)
164
+ -> std::optional<std::string>;
165
+ [[nodiscard]] auto
166
+ snappy_uncompress(const std::string& compressed) -> std::optional<std::string>;
167
+
168
+ // Signals the gateway that it may return snappy-compressed content (RFC 77: send
169
+ // COMPRESSION_ENABLED_OPTIONAL when enabled; leave the field unset when the user disabled
170
+ // compression; never COMPRESSION_ENABLED_ALWAYS).
171
+ template<typename Proto>
172
+ inline void
173
+ set_read_compression(Proto& proto, const compression_settings& compression)
174
+ {
175
+ if (compression.enabled) {
176
+ proto.set_compression(v1::COMPRESSION_ENABLED_OPTIONAL);
177
+ }
178
+ }
179
+
180
+ // Fills a write request's content oneof, snappy-compressing when maybe_compress deems it
181
+ // worthwhile.
182
+ template<typename Proto>
183
+ inline void
184
+ set_write_content(Proto& proto,
185
+ const std::vector<std::byte>& value,
186
+ const compression_settings& compression)
187
+ {
188
+ if (auto compressed = maybe_compress(value, compression)) {
189
+ proto.set_content_compressed(std::move(*compressed));
190
+ } else {
191
+ proto.set_content_uncompressed(utils::to_string(value));
192
+ }
193
+ }
194
+
195
+ // Reads a response's content oneof, snappy-decoding a compressed payload. Returns nullopt when the
196
+ // compressed arm does not decode: handing back empty bytes instead would produce a value that no
197
+ // caller can distinguish from an empty document, which is the same silent data-loss trap that made
198
+ // the unguarded oneof read wrong before compression landed. A gateway emitting an undecodable
199
+ // snappy frame is a server-side fault, so the callers surface it as internal_server_failure rather
200
+ // than inventing a value.
201
+ template<typename Proto>
202
+ inline auto
203
+ decode_content(const Proto& proto) -> std::optional<std::vector<std::byte>>
204
+ {
205
+ if (content_is_compressed(proto)) {
206
+ if (auto uncompressed = snappy_uncompress(proto.content_compressed())) {
207
+ return utils::to_binary(*uncompressed);
208
+ }
209
+ CB_LOG_DEBUG("failed to decompress snappy payload in response (compressed_size={})",
210
+ proto.content_compressed().size());
211
+ return std::nullopt;
212
+ }
213
+ return utils::to_binary(proto.content_uncompressed());
214
+ }
215
+
216
+ // ── Get ───────────────────────────────────────────────────────────────────────
217
+
218
+ inline auto
219
+ encode(const operations::get_request& request, const compression_settings& compression)
220
+ -> v1::GetRequest
221
+ {
222
+ v1::GetRequest proto;
223
+ set_location(proto, request.id);
224
+ set_read_compression(proto, compression);
225
+ return proto;
226
+ }
227
+
228
+ inline auto
229
+ decode(const v1::GetResponse& proto, key_value_error_context ctx) -> operations::get_response
230
+ {
231
+ operations::get_response response;
232
+ response.ctx = std::move(ctx);
233
+ auto value = decode_content(proto);
234
+ if (!value) {
235
+ response.ctx.override_ec(errc::common::internal_server_failure);
236
+ return response;
237
+ }
238
+ response.value = std::move(*value);
239
+ response.cas = couchbase::cas{ proto.cas() };
240
+ response.flags = proto.content_flags();
241
+ return response;
242
+ }
243
+
244
+ inline auto
245
+ encode(const operations::get_projected_request& request, const compression_settings& compression)
246
+ -> v1::GetRequest
247
+ {
248
+ v1::GetRequest proto;
249
+ set_location(proto, request.id);
250
+ set_read_compression(proto, compression);
251
+ for (const auto& path : request.projections) {
252
+ proto.add_project(path);
253
+ }
254
+ return proto;
255
+ }
256
+
257
+ inline auto
258
+ decode(const v1::GetResponse& proto,
259
+ key_value_error_context ctx,
260
+ const operations::get_projected_request& /* request */) -> operations::get_projected_response
261
+ {
262
+ operations::get_projected_response response;
263
+ response.ctx = std::move(ctx);
264
+ auto value = decode_content(proto);
265
+ if (!value) {
266
+ response.ctx.override_ec(errc::common::internal_server_failure);
267
+ return response;
268
+ }
269
+ response.value = std::move(*value);
270
+ response.cas = couchbase::cas{ proto.cas() };
271
+ response.flags = proto.content_flags();
272
+ if (proto.has_expiry()) {
273
+ response.expiry = static_cast<std::uint32_t>(proto.expiry().seconds());
274
+ }
275
+ return response;
276
+ }
277
+
278
+ // ── Mutations (upsert / insert / replace / remove) ─────────────────────────────
279
+
280
+ template<typename Response, typename Proto>
281
+ inline auto
282
+ decode_mutation(const Proto& proto, key_value_error_context ctx) -> Response
283
+ {
284
+ Response response;
285
+ response.ctx = std::move(ctx);
286
+ response.cas = couchbase::cas{ proto.cas() };
287
+ if (proto.has_mutation_token()) {
288
+ response.token = to_core_token(proto.mutation_token());
289
+ }
290
+ return response;
291
+ }
292
+
293
+ inline auto
294
+ encode(const operations::upsert_request& request, const compression_settings& compression)
295
+ -> v1::UpsertRequest
296
+ {
297
+ v1::UpsertRequest proto;
298
+ set_location(proto, request.id);
299
+ set_write_content(proto, request.value, compression);
300
+ proto.set_content_flags(request.flags);
301
+ // preserve_expiry is expressed by omitting the oneof, NOT through the proto's
302
+ // preserve_expiry_on_existing flag. The gateway rejects that flag outright whenever the oneof is
303
+ // absent -- "Cannot specify preserve expiry with no expiry, leave expiry undefined to preserve
304
+ // expiry." (kvserver.go:478-482) -- and again when the oneof carries a zero (:498-501), while a
305
+ // nil oneof already means preserve (:484). Setting both is an InvalidArgument, not a redundancy.
306
+ set_expiry(proto, request.expiry, request.preserve_expiry);
307
+ if (const auto level = to_proto_durability(request.durability_level); level) {
308
+ proto.set_durability_level(*level);
309
+ }
310
+ return proto;
311
+ }
312
+
313
+ inline auto
314
+ encode(const operations::insert_request& request, const compression_settings& compression)
315
+ -> v1::InsertRequest
316
+ {
317
+ v1::InsertRequest proto;
318
+ set_location(proto, request.id);
319
+ set_write_content(proto, request.value, compression);
320
+ proto.set_content_flags(request.flags);
321
+ // insert has no preserve_expiry: a document that does not exist yet has no expiry to preserve.
322
+ set_expiry(proto, request.expiry);
323
+ if (const auto level = to_proto_durability(request.durability_level); level) {
324
+ proto.set_durability_level(*level);
325
+ }
326
+ return proto;
327
+ }
328
+
329
+ inline auto
330
+ encode(const operations::replace_request& request, const compression_settings& compression)
331
+ -> v1::ReplaceRequest
332
+ {
333
+ v1::ReplaceRequest proto;
334
+ set_location(proto, request.id);
335
+ set_write_content(proto, request.value, compression);
336
+ proto.set_content_flags(request.flags);
337
+ if (request.cas.value() != 0) {
338
+ proto.set_cas(request.cas.value());
339
+ }
340
+ set_expiry(proto, request.expiry, request.preserve_expiry);
341
+ if (const auto level = to_proto_durability(request.durability_level); level) {
342
+ proto.set_durability_level(*level);
343
+ }
344
+ return proto;
345
+ }
346
+
347
+ inline auto
348
+ encode(const operations::remove_request& request) -> v1::RemoveRequest
349
+ {
350
+ v1::RemoveRequest proto;
351
+ set_location(proto, request.id);
352
+ if (request.cas.value() != 0) {
353
+ proto.set_cas(request.cas.value());
354
+ }
355
+ if (const auto level = to_proto_durability(request.durability_level); level) {
356
+ proto.set_durability_level(*level);
357
+ }
358
+ return proto;
359
+ }
360
+
361
+ inline auto
362
+ decode(const v1::UpsertResponse& proto, key_value_error_context ctx) -> operations::upsert_response
363
+ {
364
+ return decode_mutation<operations::upsert_response>(proto, std::move(ctx));
365
+ }
366
+
367
+ inline auto
368
+ decode(const v1::InsertResponse& proto, key_value_error_context ctx) -> operations::insert_response
369
+ {
370
+ return decode_mutation<operations::insert_response>(proto, std::move(ctx));
371
+ }
372
+
373
+ inline auto
374
+ decode(const v1::ReplaceResponse& proto, key_value_error_context ctx)
375
+ -> operations::replace_response
376
+ {
377
+ return decode_mutation<operations::replace_response>(proto, std::move(ctx));
378
+ }
379
+
380
+ inline auto
381
+ decode(const v1::RemoveResponse& proto, key_value_error_context ctx) -> operations::remove_response
382
+ {
383
+ return decode_mutation<operations::remove_response>(proto, std::move(ctx));
384
+ }
385
+
386
+ // ── Touch / Exists / lock / counters / append / prepend ────────────────────────
387
+
388
+ inline auto
389
+ encode(const operations::touch_request& request) -> v1::TouchRequest
390
+ {
391
+ v1::TouchRequest proto;
392
+ set_location(proto, request.id);
393
+ set_expiry(proto, request.expiry);
394
+ return proto;
395
+ }
396
+
397
+ inline auto
398
+ decode(const v1::TouchResponse& proto, key_value_error_context ctx) -> operations::touch_response
399
+ {
400
+ operations::touch_response response;
401
+ response.ctx = std::move(ctx);
402
+ response.cas = couchbase::cas{ proto.cas() };
403
+ return response;
404
+ }
405
+
406
+ inline auto
407
+ encode(const operations::exists_request& request) -> v1::ExistsRequest
408
+ {
409
+ v1::ExistsRequest proto;
410
+ set_location(proto, request.id);
411
+ return proto;
412
+ }
413
+
414
+ inline auto
415
+ decode(const v1::ExistsResponse& proto, key_value_error_context ctx) -> operations::exists_response
416
+ {
417
+ operations::exists_response response;
418
+ response.ctx = std::move(ctx);
419
+ response.document_exists = proto.result();
420
+ response.cas = couchbase::cas{ proto.cas() };
421
+ return response;
422
+ }
423
+
424
+ inline auto
425
+ encode(const operations::get_and_lock_request& request, const compression_settings& compression)
426
+ -> v1::GetAndLockRequest
427
+ {
428
+ v1::GetAndLockRequest proto;
429
+ set_location(proto, request.id);
430
+ proto.set_lock_time_secs(request.lock_time);
431
+ set_read_compression(proto, compression);
432
+ return proto;
433
+ }
434
+
435
+ inline auto
436
+ decode(const v1::GetAndLockResponse& proto, key_value_error_context ctx)
437
+ -> operations::get_and_lock_response
438
+ {
439
+ operations::get_and_lock_response response;
440
+ response.ctx = std::move(ctx);
441
+ auto value = decode_content(proto);
442
+ if (!value) {
443
+ response.ctx.override_ec(errc::common::internal_server_failure);
444
+ return response;
445
+ }
446
+ response.value = std::move(*value);
447
+ response.cas = couchbase::cas{ proto.cas() };
448
+ response.flags = proto.content_flags();
449
+ return response;
450
+ }
451
+
452
+ inline auto
453
+ encode(const operations::unlock_request& request) -> v1::UnlockRequest
454
+ {
455
+ v1::UnlockRequest proto;
456
+ set_location(proto, request.id);
457
+ proto.set_cas(request.cas.value());
458
+ return proto;
459
+ }
460
+
461
+ inline auto
462
+ decode(const v1::UnlockResponse& /* proto */, key_value_error_context ctx)
463
+ -> operations::unlock_response
464
+ {
465
+ operations::unlock_response response;
466
+ response.ctx = std::move(ctx);
467
+ return response;
468
+ }
469
+
470
+ inline auto
471
+ encode(const operations::get_and_touch_request& request, const compression_settings& compression)
472
+ -> v1::GetAndTouchRequest
473
+ {
474
+ v1::GetAndTouchRequest proto;
475
+ set_location(proto, request.id);
476
+ set_expiry(proto, request.expiry);
477
+ set_read_compression(proto, compression);
478
+ return proto;
479
+ }
480
+
481
+ inline auto
482
+ decode(const v1::GetAndTouchResponse& proto, key_value_error_context ctx)
483
+ -> operations::get_and_touch_response
484
+ {
485
+ operations::get_and_touch_response response;
486
+ response.ctx = std::move(ctx);
487
+ auto value = decode_content(proto);
488
+ if (!value) {
489
+ response.ctx.override_ec(errc::common::internal_server_failure);
490
+ return response;
491
+ }
492
+ response.value = std::move(*value);
493
+ response.cas = couchbase::cas{ proto.cas() };
494
+ response.flags = proto.content_flags();
495
+ return response;
496
+ }
497
+
498
+ template<typename Request, typename Proto>
499
+ inline void
500
+ set_counter_fields(Proto& proto, const Request& request)
501
+ {
502
+ set_location(proto, request.id);
503
+ proto.set_delta(request.delta);
504
+ set_expiry(proto, request.expiry);
505
+ if (request.initial_value.has_value()) {
506
+ proto.set_initial(static_cast<std::int64_t>(request.initial_value.value()));
507
+ }
508
+ if (const auto level = to_proto_durability(request.durability_level); level) {
509
+ proto.set_durability_level(*level);
510
+ }
511
+ }
512
+
513
+ template<typename Response, typename Proto>
514
+ inline auto
515
+ decode_counter(const Proto& proto, key_value_error_context ctx) -> Response
516
+ {
517
+ Response response;
518
+ response.ctx = std::move(ctx);
519
+ response.content = static_cast<std::uint64_t>(proto.content());
520
+ response.cas = couchbase::cas{ proto.cas() };
521
+ if (proto.has_mutation_token()) {
522
+ response.token = to_core_token(proto.mutation_token());
523
+ }
524
+ return response;
525
+ }
526
+
527
+ inline auto
528
+ encode(const operations::increment_request& request) -> v1::IncrementRequest
529
+ {
530
+ v1::IncrementRequest proto;
531
+ set_counter_fields(proto, request);
532
+ return proto;
533
+ }
534
+
535
+ inline auto
536
+ decode(const v1::IncrementResponse& proto, key_value_error_context ctx)
537
+ -> operations::increment_response
538
+ {
539
+ return decode_counter<operations::increment_response>(proto, std::move(ctx));
540
+ }
541
+
542
+ inline auto
543
+ encode(const operations::decrement_request& request) -> v1::DecrementRequest
544
+ {
545
+ v1::DecrementRequest proto;
546
+ set_counter_fields(proto, request);
547
+ return proto;
548
+ }
549
+
550
+ inline auto
551
+ decode(const v1::DecrementResponse& proto, key_value_error_context ctx)
552
+ -> operations::decrement_response
553
+ {
554
+ return decode_counter<operations::decrement_response>(proto, std::move(ctx));
555
+ }
556
+
557
+ inline auto
558
+ encode(const operations::append_request& request) -> v1::AppendRequest
559
+ {
560
+ v1::AppendRequest proto;
561
+ set_location(proto, request.id);
562
+ proto.set_content(utils::to_string(request.value));
563
+ if (request.cas.value() != 0) {
564
+ proto.set_cas(request.cas.value());
565
+ }
566
+ if (const auto level = to_proto_durability(request.durability_level); level) {
567
+ proto.set_durability_level(*level);
568
+ }
569
+ return proto;
570
+ }
571
+
572
+ inline auto
573
+ decode(const v1::AppendResponse& proto, key_value_error_context ctx) -> operations::append_response
574
+ {
575
+ return decode_mutation<operations::append_response>(proto, std::move(ctx));
576
+ }
577
+
578
+ inline auto
579
+ encode(const operations::prepend_request& request) -> v1::PrependRequest
580
+ {
581
+ v1::PrependRequest proto;
582
+ set_location(proto, request.id);
583
+ proto.set_content(utils::to_string(request.value));
584
+ if (request.cas.value() != 0) {
585
+ proto.set_cas(request.cas.value());
586
+ }
587
+ if (const auto level = to_proto_durability(request.durability_level); level) {
588
+ proto.set_durability_level(*level);
589
+ }
590
+ return proto;
591
+ }
592
+
593
+ inline auto
594
+ decode(const v1::PrependResponse& proto, key_value_error_context ctx)
595
+ -> operations::prepend_response
596
+ {
597
+ return decode_mutation<operations::prepend_response>(proto, std::move(ctx));
598
+ }
599
+
600
+ } // namespace couchbase::core::protostellar::kv