couchbase 3.4.2 → 3.4.4

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 (355) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +71 -7
  4. data/ext/couchbase/cmake/Documentation.cmake +0 -1
  5. data/ext/couchbase/cmake/OpenSSL.cmake +98 -3
  6. data/ext/couchbase/cmake/Testing.cmake +12 -4
  7. data/ext/couchbase/cmake/build_config.hxx.in +3 -0
  8. data/ext/couchbase/core/bucket.cxx +183 -151
  9. data/ext/couchbase/core/bucket.hxx +23 -1
  10. data/ext/couchbase/core/cluster.hxx +51 -13
  11. data/ext/couchbase/core/cluster_options.cxx +2 -2
  12. data/ext/couchbase/core/cluster_options.hxx +7 -6
  13. data/ext/couchbase/core/cluster_options_fwd.hxx +26 -0
  14. data/ext/couchbase/core/config_profile.hxx +1 -54
  15. data/ext/couchbase/core/config_profiles.cxx +79 -0
  16. data/ext/couchbase/core/config_profiles.hxx +56 -0
  17. data/ext/couchbase/core/crud_component.cxx +51 -22
  18. data/ext/couchbase/core/error_context/key_value.cxx +2 -1
  19. data/ext/couchbase/core/error_context/key_value.hxx +10 -12
  20. data/ext/couchbase/core/error_context/search.hxx +1 -1
  21. data/ext/couchbase/core/impl/analytics.cxx +1 -0
  22. data/ext/couchbase/core/impl/boolean_field_query.cxx +40 -0
  23. data/ext/couchbase/core/impl/boolean_query.cxx +62 -0
  24. data/ext/couchbase/core/impl/build_deferred_query_indexes.cxx +115 -50
  25. data/ext/couchbase/core/impl/cluster.cxx +8 -0
  26. data/ext/couchbase/core/impl/conjunction_query.cxx +51 -0
  27. data/ext/couchbase/core/impl/create_bucket.cxx +155 -0
  28. data/ext/couchbase/core/impl/create_query_index.cxx +172 -59
  29. data/ext/couchbase/core/impl/date_range.cxx +89 -0
  30. data/ext/couchbase/core/impl/date_range_facet.cxx +54 -0
  31. data/ext/couchbase/core/impl/date_range_facet_result.cxx +64 -0
  32. data/ext/couchbase/core/impl/date_range_query.cxx +125 -0
  33. data/ext/couchbase/core/impl/disjunction_query.cxx +51 -0
  34. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +2 -1
  35. data/ext/couchbase/core/impl/drop_bucket.cxx +66 -0
  36. data/ext/couchbase/core/impl/drop_query_index.cxx +138 -59
  37. data/ext/couchbase/core/impl/encoded_search_facet.hxx +29 -0
  38. data/ext/couchbase/core/impl/encoded_search_query.hxx +29 -0
  39. data/ext/couchbase/core/impl/encoded_search_sort.hxx +29 -0
  40. data/ext/couchbase/core/impl/flush_bucket.cxx +66 -0
  41. data/ext/couchbase/core/impl/geo_bounding_box_query.cxx +46 -0
  42. data/ext/couchbase/core/impl/geo_distance_query.cxx +43 -0
  43. data/ext/couchbase/core/impl/geo_polygon_query.cxx +46 -0
  44. data/ext/couchbase/core/impl/get_all_buckets.cxx +163 -0
  45. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +67 -37
  46. data/ext/couchbase/core/impl/get_bucket.cxx +153 -0
  47. data/ext/couchbase/core/impl/internal_date_range_facet_result.cxx +80 -0
  48. data/ext/couchbase/core/impl/internal_date_range_facet_result.hxx +48 -0
  49. data/ext/couchbase/core/impl/internal_manager_error_context.cxx +113 -0
  50. data/ext/couchbase/core/impl/internal_manager_error_context.hxx +60 -0
  51. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.cxx +80 -0
  52. data/ext/couchbase/core/impl/internal_numeric_range_facet_result.hxx +48 -0
  53. data/ext/couchbase/core/impl/internal_search_error_context.cxx +141 -0
  54. data/ext/couchbase/core/impl/internal_search_error_context.hxx +61 -0
  55. data/ext/couchbase/core/impl/internal_search_meta_data.cxx +60 -0
  56. data/ext/couchbase/core/impl/internal_search_meta_data.hxx +41 -0
  57. data/ext/couchbase/core/impl/internal_search_result.cxx +84 -0
  58. data/ext/couchbase/core/impl/internal_search_result.hxx +43 -0
  59. data/ext/couchbase/core/impl/internal_search_row.cxx +82 -0
  60. data/ext/couchbase/core/impl/internal_search_row.hxx +56 -0
  61. data/ext/couchbase/core/impl/internal_search_row_location.hxx +32 -0
  62. data/ext/couchbase/core/impl/internal_search_row_locations.cxx +137 -0
  63. data/ext/couchbase/core/impl/internal_search_row_locations.hxx +45 -0
  64. data/ext/couchbase/core/impl/internal_term_facet_result.cxx +80 -0
  65. data/ext/couchbase/core/impl/internal_term_facet_result.hxx +48 -0
  66. data/ext/couchbase/core/impl/key_value_error_category.cxx +2 -4
  67. data/ext/couchbase/core/impl/key_value_error_context.cxx +98 -0
  68. data/ext/couchbase/core/impl/lookup_in.cxx +1 -0
  69. data/ext/couchbase/core/impl/lookup_in_all_replicas.cxx +176 -0
  70. data/ext/couchbase/core/impl/lookup_in_all_replicas.hxx +80 -0
  71. data/ext/couchbase/core/impl/lookup_in_any_replica.cxx +167 -0
  72. data/ext/couchbase/core/impl/lookup_in_any_replica.hxx +75 -0
  73. data/ext/couchbase/core/impl/lookup_in_replica.cxx +97 -0
  74. data/ext/couchbase/core/impl/lookup_in_replica.hxx +67 -0
  75. data/ext/couchbase/core/impl/manager_error_context.cxx +100 -0
  76. data/ext/couchbase/core/impl/match_all_query.cxx +35 -0
  77. data/ext/couchbase/core/impl/match_none_query.cxx +35 -0
  78. data/ext/couchbase/core/impl/match_phrase_query.cxx +43 -0
  79. data/ext/couchbase/core/impl/match_query.cxx +59 -0
  80. data/ext/couchbase/core/impl/numeric_range.cxx +49 -0
  81. data/ext/couchbase/core/impl/numeric_range_facet.cxx +54 -0
  82. data/ext/couchbase/core/impl/numeric_range_facet_result.cxx +64 -0
  83. data/ext/couchbase/core/impl/numeric_range_query.cxx +56 -0
  84. data/ext/couchbase/core/impl/phrase_query.cxx +42 -0
  85. data/ext/couchbase/core/impl/prefix_query.cxx +40 -0
  86. data/ext/couchbase/core/impl/query.cxx +1 -0
  87. data/ext/couchbase/core/impl/query_error_context.cxx +75 -0
  88. data/ext/couchbase/core/impl/query_string_query.cxx +37 -0
  89. data/ext/couchbase/core/impl/regexp_query.cxx +40 -0
  90. data/ext/couchbase/core/impl/search.cxx +191 -0
  91. data/ext/couchbase/core/impl/search_error_context.cxx +147 -0
  92. data/ext/couchbase/core/impl/search_meta_data.cxx +46 -0
  93. data/ext/couchbase/core/impl/search_result.cxx +66 -0
  94. data/ext/couchbase/core/impl/search_row.cxx +74 -0
  95. data/ext/couchbase/core/impl/search_row_location.cxx +64 -0
  96. data/ext/couchbase/core/impl/search_row_locations.cxx +66 -0
  97. data/ext/couchbase/core/impl/search_sort_field.cxx +104 -0
  98. data/ext/couchbase/core/impl/search_sort_id.cxx +43 -0
  99. data/ext/couchbase/core/impl/search_sort_score.cxx +43 -0
  100. data/ext/couchbase/core/impl/term_facet.cxx +36 -0
  101. data/ext/couchbase/core/impl/term_facet_result.cxx +64 -0
  102. data/ext/couchbase/core/impl/term_query.cxx +56 -0
  103. data/ext/couchbase/core/impl/term_range_query.cxx +57 -0
  104. data/ext/couchbase/core/impl/update_bucket.cxx +130 -0
  105. data/ext/couchbase/core/impl/watch_query_indexes.cxx +53 -29
  106. data/ext/couchbase/core/impl/wildcard_query.cxx +40 -0
  107. data/ext/couchbase/core/io/dns_client.cxx +111 -40
  108. data/ext/couchbase/core/io/dns_config.cxx +5 -4
  109. data/ext/couchbase/core/io/http_context.hxx +1 -1
  110. data/ext/couchbase/core/io/http_session.hxx +34 -1
  111. data/ext/couchbase/core/io/http_session_manager.hxx +5 -3
  112. data/ext/couchbase/core/io/mcbp_command.hxx +9 -2
  113. data/ext/couchbase/core/io/mcbp_session.cxx +106 -42
  114. data/ext/couchbase/core/io/mcbp_session.hxx +4 -3
  115. data/ext/couchbase/core/io/retry_orchestrator.hxx +3 -2
  116. data/ext/couchbase/core/json_string.hxx +5 -0
  117. data/ext/couchbase/core/logger/custom_rotating_file_sink.cxx +1 -1
  118. data/ext/couchbase/core/logger/logger.cxx +80 -20
  119. data/ext/couchbase/core/logger/logger.hxx +31 -0
  120. data/ext/couchbase/core/meta/features.hxx +25 -0
  121. data/ext/couchbase/core/meta/version.cxx +18 -4
  122. data/ext/couchbase/core/mozilla_ca_bundle.hxx +39 -0
  123. data/ext/couchbase/core/operations/document_analytics.cxx +1 -0
  124. data/ext/couchbase/core/operations/document_analytics.hxx +1 -0
  125. data/ext/couchbase/core/operations/document_append.hxx +1 -1
  126. data/ext/couchbase/core/operations/document_decrement.hxx +1 -1
  127. data/ext/couchbase/core/operations/document_exists.hxx +1 -1
  128. data/ext/couchbase/core/operations/document_get.hxx +1 -1
  129. data/ext/couchbase/core/operations/document_get_and_lock.hxx +1 -1
  130. data/ext/couchbase/core/operations/document_get_and_touch.hxx +1 -1
  131. data/ext/couchbase/core/operations/document_get_projected.hxx +1 -1
  132. data/ext/couchbase/core/operations/document_increment.hxx +1 -1
  133. data/ext/couchbase/core/operations/document_insert.hxx +1 -1
  134. data/ext/couchbase/core/operations/document_lookup_in.hxx +1 -1
  135. data/ext/couchbase/core/operations/document_lookup_in_all_replicas.hxx +192 -0
  136. data/ext/couchbase/core/operations/document_lookup_in_any_replica.hxx +188 -0
  137. data/ext/couchbase/core/operations/document_mutate_in.hxx +1 -1
  138. data/ext/couchbase/core/operations/document_prepend.hxx +1 -1
  139. data/ext/couchbase/core/operations/document_query.cxx +13 -0
  140. data/ext/couchbase/core/operations/document_query.hxx +7 -0
  141. data/ext/couchbase/core/operations/document_remove.hxx +1 -1
  142. data/ext/couchbase/core/operations/document_replace.hxx +1 -1
  143. data/ext/couchbase/core/operations/document_search.cxx +4 -1
  144. data/ext/couchbase/core/operations/document_search.hxx +2 -1
  145. data/ext/couchbase/core/operations/document_touch.hxx +1 -1
  146. data/ext/couchbase/core/operations/document_unlock.hxx +1 -1
  147. data/ext/couchbase/core/operations/document_upsert.hxx +1 -1
  148. data/ext/couchbase/core/operations/document_view.hxx +1 -0
  149. data/ext/couchbase/core/operations.hxx +2 -0
  150. data/ext/couchbase/core/origin.cxx +270 -0
  151. data/ext/couchbase/core/origin.hxx +2 -0
  152. data/ext/couchbase/core/protocol/client_request.hxx +11 -2
  153. data/ext/couchbase/core/protocol/client_response.hxx +1 -0
  154. data/ext/couchbase/core/protocol/cmd_hello.hxx +1 -0
  155. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.cxx +107 -0
  156. data/ext/couchbase/core/protocol/cmd_lookup_in_replica.hxx +137 -0
  157. data/ext/couchbase/core/protocol/hello_feature.hxx +6 -0
  158. data/ext/couchbase/core/protocol/hello_feature_fmt.hxx +3 -0
  159. data/ext/couchbase/core/protocol/status.cxx +2 -2
  160. data/ext/couchbase/core/public_fwd.hxx +21 -0
  161. data/ext/couchbase/core/range_scan_options.cxx +3 -27
  162. data/ext/couchbase/core/range_scan_options.hxx +13 -17
  163. data/ext/couchbase/core/range_scan_orchestrator.cxx +388 -170
  164. data/ext/couchbase/core/range_scan_orchestrator.hxx +13 -2
  165. data/ext/couchbase/core/range_scan_orchestrator_options.hxx +5 -3
  166. data/ext/couchbase/core/scan_options.hxx +0 -19
  167. data/ext/couchbase/core/scan_result.cxx +19 -5
  168. data/ext/couchbase/core/scan_result.hxx +5 -2
  169. data/ext/couchbase/core/timeout_defaults.hxx +2 -3
  170. data/ext/couchbase/core/tls_verify_mode.hxx +26 -0
  171. data/ext/couchbase/core/topology/capabilities.hxx +3 -0
  172. data/ext/couchbase/core/topology/capabilities_fmt.hxx +8 -0
  173. data/ext/couchbase/core/topology/collections_manifest_fmt.hxx +1 -1
  174. data/ext/couchbase/core/topology/configuration.cxx +15 -2
  175. data/ext/couchbase/core/topology/configuration.hxx +20 -1
  176. data/ext/couchbase/core/topology/configuration_json.hxx +6 -1
  177. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.cxx +93 -0
  178. data/ext/couchbase/core/transactions/attempt_context_testing_hooks.hxx +48 -75
  179. data/ext/couchbase/core/transactions/cleanup_testing_hooks.cxx +52 -0
  180. data/ext/couchbase/core/transactions/cleanup_testing_hooks.hxx +17 -31
  181. data/ext/couchbase/core/transactions/exceptions.hxx +12 -9
  182. data/ext/couchbase/core/utils/connection_string.cxx +75 -43
  183. data/ext/couchbase/core/utils/connection_string.hxx +1 -0
  184. data/ext/couchbase/core/utils/json.cxx +4 -1
  185. data/ext/couchbase/couchbase/analytics_error_context.hxx +1 -1
  186. data/ext/couchbase/couchbase/behavior_options.hxx +27 -1
  187. data/ext/couchbase/couchbase/boolean_field_query.hxx +77 -0
  188. data/ext/couchbase/couchbase/boolean_query.hxx +223 -0
  189. data/ext/couchbase/couchbase/bucket_manager.hxx +135 -0
  190. data/ext/couchbase/couchbase/build_query_index_options.hxx +0 -30
  191. data/ext/couchbase/couchbase/cluster.hxx +56 -1
  192. data/ext/couchbase/couchbase/collection.hxx +111 -0
  193. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +7 -48
  194. data/ext/couchbase/couchbase/conjunction_query.hxx +88 -0
  195. data/ext/couchbase/couchbase/create_bucket_options.hxx +41 -0
  196. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +0 -29
  197. data/ext/couchbase/couchbase/create_query_index_options.hxx +0 -33
  198. data/ext/couchbase/couchbase/date_range.hxx +69 -0
  199. data/ext/couchbase/couchbase/date_range_facet.hxx +56 -0
  200. data/ext/couchbase/couchbase/date_range_facet_result.hxx +55 -0
  201. data/ext/couchbase/couchbase/date_range_query.hxx +265 -0
  202. data/ext/couchbase/couchbase/disjunction_query.hxx +109 -0
  203. data/ext/couchbase/couchbase/doc_id_query.hxx +111 -0
  204. data/ext/couchbase/couchbase/drop_bucket_options.hxx +41 -0
  205. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +0 -30
  206. data/ext/couchbase/couchbase/drop_query_index_options.hxx +0 -31
  207. data/ext/couchbase/couchbase/error_codes.hxx +1 -2
  208. data/ext/couchbase/couchbase/error_context.hxx +17 -8
  209. data/ext/couchbase/couchbase/flush_bucket_options.hxx +41 -0
  210. data/ext/couchbase/couchbase/fmt/analytics_scan_consistency.hxx +52 -0
  211. data/ext/couchbase/{core/topology/error_map_fmt.hxx → couchbase/fmt/key_value_error_map_attribute.hxx} +21 -21
  212. data/ext/couchbase/couchbase/fmt/search_scan_consistency.hxx +49 -0
  213. data/ext/couchbase/couchbase/geo_bounding_box_query.hxx +107 -0
  214. data/ext/couchbase/couchbase/geo_distance_query.hxx +109 -0
  215. data/ext/couchbase/couchbase/geo_point.hxx +32 -0
  216. data/ext/couchbase/couchbase/geo_polygon_query.hxx +85 -0
  217. data/ext/couchbase/couchbase/get_all_buckets_options.hxx +44 -0
  218. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +0 -30
  219. data/ext/couchbase/couchbase/get_and_lock_options.hxx +2 -2
  220. data/ext/couchbase/couchbase/get_and_touch_options.hxx +2 -2
  221. data/ext/couchbase/couchbase/get_bucket_options.hxx +43 -0
  222. data/ext/couchbase/couchbase/get_options.hxx +2 -2
  223. data/ext/couchbase/couchbase/highlight_style.hxx +45 -0
  224. data/ext/couchbase/couchbase/insert_options.hxx +3 -3
  225. data/ext/couchbase/couchbase/key_value_error_context.hxx +7 -2
  226. data/ext/couchbase/couchbase/lookup_in_all_replicas_options.hxx +109 -0
  227. data/ext/couchbase/couchbase/lookup_in_any_replica_options.hxx +101 -0
  228. data/ext/couchbase/couchbase/lookup_in_options.hxx +2 -2
  229. data/ext/couchbase/couchbase/lookup_in_replica_result.hxx +74 -0
  230. data/ext/couchbase/couchbase/lookup_in_result.hxx +26 -0
  231. data/ext/couchbase/couchbase/management/bucket_settings.hxx +116 -0
  232. data/ext/couchbase/couchbase/manager_error_context.hxx +29 -53
  233. data/ext/couchbase/couchbase/match_all_query.hxx +43 -0
  234. data/ext/couchbase/couchbase/match_none_query.hxx +43 -0
  235. data/ext/couchbase/couchbase/match_operator.hxx +45 -0
  236. data/ext/couchbase/couchbase/match_phrase_query.hxx +108 -0
  237. data/ext/couchbase/couchbase/match_query.hxx +163 -0
  238. data/ext/couchbase/couchbase/mutate_in_options.hxx +2 -2
  239. data/ext/couchbase/couchbase/numeric_range.hxx +58 -0
  240. data/ext/couchbase/couchbase/numeric_range_facet.hxx +56 -0
  241. data/ext/couchbase/couchbase/numeric_range_facet_result.hxx +55 -0
  242. data/ext/couchbase/couchbase/numeric_range_query.hxx +143 -0
  243. data/ext/couchbase/couchbase/phrase_query.hxx +93 -0
  244. data/ext/couchbase/couchbase/prefix_query.hxx +82 -0
  245. data/ext/couchbase/couchbase/query_error_context.hxx +3 -1
  246. data/ext/couchbase/couchbase/query_index_manager.hxx +16 -83
  247. data/ext/couchbase/couchbase/query_options.hxx +18 -0
  248. data/ext/couchbase/couchbase/query_string_query.hxx +72 -0
  249. data/ext/couchbase/couchbase/regexp_query.hxx +82 -0
  250. data/ext/couchbase/couchbase/remove_options.hxx +2 -2
  251. data/ext/couchbase/couchbase/replace_options.hxx +3 -3
  252. data/ext/couchbase/couchbase/scope.hxx +40 -0
  253. data/ext/couchbase/couchbase/search_date_range.hxx +68 -0
  254. data/ext/couchbase/couchbase/search_error_context.hxx +138 -0
  255. data/ext/couchbase/couchbase/search_facet.hxx +60 -0
  256. data/ext/couchbase/couchbase/search_facet_result.hxx +50 -0
  257. data/ext/couchbase/couchbase/search_meta_data.hxx +85 -0
  258. data/ext/couchbase/couchbase/search_metrics.hxx +127 -0
  259. data/ext/couchbase/couchbase/search_numeric_range.hxx +69 -0
  260. data/ext/couchbase/couchbase/search_options.hxx +509 -0
  261. data/ext/couchbase/couchbase/search_query.hxx +69 -0
  262. data/ext/couchbase/couchbase/search_result.hxx +77 -0
  263. data/ext/couchbase/couchbase/search_row.hxx +104 -0
  264. data/ext/couchbase/couchbase/search_row_location.hxx +55 -0
  265. data/ext/couchbase/couchbase/search_row_locations.hxx +86 -0
  266. data/ext/couchbase/couchbase/search_scan_consistency.hxx +34 -0
  267. data/ext/couchbase/couchbase/search_sort.hxx +58 -0
  268. data/ext/couchbase/couchbase/search_sort_field.hxx +117 -0
  269. data/ext/couchbase/couchbase/search_sort_field_missing.hxx +26 -0
  270. data/ext/couchbase/couchbase/search_sort_field_mode.hxx +27 -0
  271. data/ext/couchbase/couchbase/search_sort_field_type.hxx +28 -0
  272. data/ext/couchbase/couchbase/search_sort_id.hxx +60 -0
  273. data/ext/couchbase/couchbase/search_sort_score.hxx +60 -0
  274. data/ext/couchbase/couchbase/search_term_range.hxx +51 -0
  275. data/ext/couchbase/couchbase/security_options.hxx +18 -0
  276. data/ext/couchbase/couchbase/subdocument_error_context.hxx +4 -2
  277. data/ext/couchbase/couchbase/term_facet.hxx +48 -0
  278. data/ext/couchbase/couchbase/term_facet_result.hxx +55 -0
  279. data/ext/couchbase/couchbase/term_query.hxx +151 -0
  280. data/ext/couchbase/couchbase/term_range_query.hxx +142 -0
  281. data/ext/couchbase/couchbase/touch_options.hxx +2 -2
  282. data/ext/couchbase/couchbase/tracing/request_span.hxx +63 -0
  283. data/ext/couchbase/couchbase/tracing/request_tracer.hxx +2 -40
  284. data/ext/couchbase/couchbase/transactions/async_attempt_context.hxx +83 -4
  285. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +67 -0
  286. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +2 -0
  287. data/ext/couchbase/couchbase/transactions/transaction_keyspace.hxx +11 -1
  288. data/ext/couchbase/couchbase/transactions/transaction_options.hxx +79 -8
  289. data/ext/couchbase/couchbase/transactions/transaction_query_options.hxx +128 -15
  290. data/ext/couchbase/couchbase/transactions/transaction_query_result.hxx +4 -0
  291. data/ext/couchbase/couchbase/transactions/transaction_result.hxx +1 -1
  292. data/ext/couchbase/couchbase/transactions/transactions_cleanup_config.hxx +5 -3
  293. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +9 -5
  294. data/ext/couchbase/couchbase/transactions/transactions_query_config.hxx +6 -3
  295. data/ext/couchbase/couchbase/transactions.hxx +34 -1
  296. data/ext/couchbase/couchbase/unlock_options.hxx +2 -2
  297. data/ext/couchbase/couchbase/update_bucket_options.hxx +41 -0
  298. data/ext/couchbase/couchbase/upsert_options.hxx +3 -3
  299. data/ext/couchbase/couchbase/watch_query_indexes_options.hxx +0 -31
  300. data/ext/couchbase/couchbase/wildcard_query.hxx +83 -0
  301. data/ext/couchbase/test/CMakeLists.txt +8 -5
  302. data/ext/couchbase/test/benchmark_helper_integration.hxx +2 -2
  303. data/ext/couchbase/test/test_helper.hxx +5 -5
  304. data/ext/couchbase/test/test_integration_analytics.cxx +28 -6
  305. data/ext/couchbase/test/test_integration_collections.cxx +13 -3
  306. data/ext/couchbase/test/test_integration_connect.cxx +7 -3
  307. data/ext/couchbase/test/test_integration_crud.cxx +18 -3
  308. data/ext/couchbase/test/test_integration_diagnostics.cxx +11 -5
  309. data/ext/couchbase/test/test_integration_durability.cxx +12 -7
  310. data/ext/couchbase/test/test_integration_examples.cxx +419 -11
  311. data/ext/couchbase/test/test_integration_management.cxx +867 -368
  312. data/ext/couchbase/test/test_integration_query.cxx +87 -17
  313. data/ext/couchbase/test/test_integration_range_scan.cxx +363 -124
  314. data/ext/couchbase/test/test_integration_read_replica.cxx +48 -11
  315. data/ext/couchbase/test/test_integration_search.cxx +32 -3
  316. data/ext/couchbase/test/test_integration_subdoc.cxx +717 -11
  317. data/ext/couchbase/test/test_integration_tracer.cxx +5 -0
  318. data/ext/couchbase/test/test_integration_transcoders.cxx +13 -5
  319. data/ext/couchbase/test/{test_transaction_transaction_context.cxx → test_transaction_context.cxx} +1 -1
  320. data/ext/couchbase/test/test_transaction_examples.cxx +195 -0
  321. data/ext/couchbase/test/{test_transaction_transaction_public_async_api.cxx → test_transaction_public_async_api.cxx} +13 -12
  322. data/ext/couchbase/test/{test_transaction_transaction_public_blocking_api.cxx → test_transaction_public_blocking_api.cxx} +27 -21
  323. data/ext/couchbase/test/{test_transaction_transaction_simple.cxx → test_transaction_simple.cxx} +17 -5
  324. data/ext/couchbase/test/{test_transaction_transaction_simple_async.cxx → test_transaction_simple_async.cxx} +19 -21
  325. data/ext/couchbase/test/test_unit_config_profiles.cxx +1 -1
  326. data/ext/couchbase/test/test_unit_connection_string.cxx +29 -0
  327. data/ext/couchbase/test/test_unit_json_transcoder.cxx +4 -0
  328. data/ext/couchbase/test/test_unit_query.cxx +75 -0
  329. data/ext/couchbase/test/test_unit_search.cxx +427 -0
  330. data/ext/couchbase/test/test_unit_transaction_utils.cxx +10 -1
  331. data/ext/couchbase/test/test_unit_utils.cxx +8 -4
  332. data/ext/couchbase.cxx +641 -45
  333. data/ext/revisions.rb +3 -3
  334. data/lib/couchbase/authenticator.rb +0 -1
  335. data/lib/couchbase/cluster.rb +1 -5
  336. data/lib/couchbase/collection.rb +108 -0
  337. data/lib/couchbase/collection_options.rb +100 -0
  338. data/lib/couchbase/config_profiles.rb +1 -1
  339. data/lib/couchbase/errors.rb +5 -0
  340. data/lib/couchbase/json_transcoder.rb +12 -5
  341. data/lib/couchbase/key_value_scan.rb +125 -0
  342. data/lib/couchbase/management/collection_query_index_manager.rb +54 -15
  343. data/lib/couchbase/management/query_index_manager.rb +70 -5
  344. data/lib/couchbase/options.rb +151 -0
  345. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  346. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  347. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  348. data/lib/couchbase/scope.rb +1 -1
  349. data/lib/couchbase/search_options.rb +5 -0
  350. data/lib/couchbase/transcoder_flags.rb +62 -0
  351. data/lib/couchbase/utils/time.rb +14 -1
  352. data/lib/couchbase/version.rb +1 -1
  353. metadata +175 -13
  354. data/ext/couchbase/core/config_profile.cxx +0 -47
  355. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +0 -93
@@ -30,7 +30,7 @@ assert_single_lookup_success(test::utils::integration_test_guard& integration,
30
30
  couchbase::core::operations::lookup_in_request req{ id };
31
31
  req.specs = couchbase::lookup_in_specs{ spec }.specs();
32
32
  auto resp = test::utils::execute(integration.cluster, req);
33
- INFO(fmt::format("assert_single_lookup_success(\"{}\", \"{}\")", id, req.specs[0].path_))
33
+ INFO(fmt::format("assert_single_lookup_success(\"{}\", \"{}\")", id, req.specs[0].path_));
34
34
  REQUIRE_SUCCESS(resp.ctx.ec());
35
35
  REQUIRE_FALSE(resp.cas.empty());
36
36
  REQUIRE(resp.fields.size() == 1);
@@ -54,7 +54,7 @@ assert_single_lookup_error(test::utils::integration_test_guard& integration,
54
54
  couchbase::core::operations::lookup_in_request req{ id };
55
55
  req.specs = couchbase::lookup_in_specs{ spec }.specs();
56
56
  auto resp = test::utils::execute(integration.cluster, req);
57
- INFO(fmt::format("assert_single_lookup_error(\"{}\", \"{}\")", id, req.specs[0].path_))
57
+ INFO(fmt::format("assert_single_lookup_error(\"{}\", \"{}\")", id, req.specs[0].path_));
58
58
  REQUIRE_SUCCESS(resp.ctx.ec());
59
59
  REQUIRE_FALSE(resp.cas.empty());
60
60
  REQUIRE(resp.fields.size() == 1);
@@ -65,6 +65,108 @@ assert_single_lookup_error(test::utils::integration_test_guard& integration,
65
65
  REQUIRE(resp.fields[0].ec == expected_ec);
66
66
  }
67
67
 
68
+ template<typename SubdocumentOperation>
69
+ void
70
+ assert_single_lookup_any_replica_success(test::utils::integration_test_guard& integration,
71
+ const couchbase::core::document_id& id,
72
+ const SubdocumentOperation& spec,
73
+ std::optional<std::string> expected_value = std::nullopt)
74
+ {
75
+ couchbase::core::operations::lookup_in_any_replica_request req{ id };
76
+ req.specs = couchbase::lookup_in_specs{ spec }.specs();
77
+ auto resp = test::utils::execute(integration.cluster, req);
78
+ INFO(fmt::format("assert_single_lookup_all_replica_success(\"{}\", \"{}\")", id, req.specs[0].path_));
79
+ REQUIRE_SUCCESS(resp.ctx.ec());
80
+ REQUIRE_FALSE(resp.cas.empty());
81
+ REQUIRE(resp.fields.size() == 1);
82
+ REQUIRE(resp.fields[0].exists);
83
+ REQUIRE(resp.fields[0].path == req.specs[0].path_);
84
+ REQUIRE(resp.fields[0].status == couchbase::key_value_status_code::success);
85
+ REQUIRE_SUCCESS(resp.fields[0].ec);
86
+ if (expected_value.has_value()) {
87
+ REQUIRE(couchbase::core::utils::to_binary(expected_value.value()) == resp.fields[0].value);
88
+ }
89
+ }
90
+
91
+ template<typename SubdocumentOperation>
92
+ void
93
+ assert_single_lookup_any_replica_error(test::utils::integration_test_guard& integration,
94
+ const couchbase::core::document_id& id,
95
+ const SubdocumentOperation& spec,
96
+ couchbase::key_value_status_code expected_status,
97
+ std::error_code expected_ec)
98
+ {
99
+ couchbase::core::operations::lookup_in_any_replica_request req{ id };
100
+ req.specs = couchbase::lookup_in_specs{ spec }.specs();
101
+ auto resp = test::utils::execute(integration.cluster, req);
102
+ INFO(fmt::format("assert_single_lookup_all_replica_error(\"{}\", \"{}\")", id, req.specs[0].path_));
103
+ REQUIRE_SUCCESS(resp.ctx.ec());
104
+ REQUIRE_FALSE(resp.cas.empty());
105
+ REQUIRE(resp.fields.size() == 1);
106
+ REQUIRE_FALSE(resp.fields[0].exists);
107
+ REQUIRE(resp.fields[0].path == req.specs[0].path_);
108
+ REQUIRE(resp.fields[0].value.empty());
109
+ REQUIRE(resp.fields[0].status == expected_status);
110
+ REQUIRE(resp.fields[0].ec == expected_ec);
111
+ }
112
+
113
+ template<typename SubdocumentOperation>
114
+ void
115
+ assert_single_lookup_all_replica_success(test::utils::integration_test_guard& integration,
116
+ const couchbase::core::document_id& id,
117
+ const SubdocumentOperation& spec,
118
+ std::optional<std::string> expected_value = std::nullopt)
119
+ {
120
+ couchbase::core::operations::lookup_in_all_replicas_request req{ id };
121
+ req.specs = couchbase::lookup_in_specs{ spec }.specs();
122
+ auto response = test::utils::execute(integration.cluster, req);
123
+ INFO(fmt::format("assert_single_lookup_all_replica_success(\"{}\", \"{}\")", id, req.specs[0].path_));
124
+ REQUIRE_SUCCESS(response.ctx.ec());
125
+ REQUIRE(response.entries.size() == integration.number_of_replicas() + 1);
126
+ auto responses_from_active =
127
+ std::count_if(response.entries.begin(), response.entries.end(), [](const auto& r) { return !r.is_replica; });
128
+ REQUIRE(responses_from_active == 1);
129
+ for (auto& resp : response.entries) {
130
+ REQUIRE_FALSE(resp.cas.empty());
131
+ REQUIRE(resp.fields.size() == 1);
132
+ REQUIRE(resp.fields[0].exists);
133
+ REQUIRE(resp.fields[0].path == req.specs[0].path_);
134
+ REQUIRE(resp.fields[0].status == couchbase::key_value_status_code::success);
135
+ REQUIRE_SUCCESS(resp.fields[0].ec);
136
+ if (expected_value.has_value()) {
137
+ REQUIRE(couchbase::core::utils::to_binary(expected_value.value()) == resp.fields[0].value);
138
+ }
139
+ }
140
+ }
141
+
142
+ template<typename SubdocumentOperation>
143
+ void
144
+ assert_single_lookup_all_replica_error(test::utils::integration_test_guard& integration,
145
+ const couchbase::core::document_id& id,
146
+ const SubdocumentOperation& spec,
147
+ couchbase::key_value_status_code expected_status,
148
+ std::error_code expected_ec)
149
+ {
150
+ couchbase::core::operations::lookup_in_all_replicas_request req{ id };
151
+ req.specs = couchbase::lookup_in_specs{ spec }.specs();
152
+ auto response = test::utils::execute(integration.cluster, req);
153
+ INFO(fmt::format("assert_single_lookup_all_replica_error(\"{}\", \"{}\")", id, req.specs[0].path_));
154
+ REQUIRE_SUCCESS(response.ctx.ec());
155
+ REQUIRE(response.entries.size() == integration.number_of_replicas() + 1);
156
+ auto responses_from_active =
157
+ std::count_if(response.entries.begin(), response.entries.end(), [](const auto& r) { return !r.is_replica; });
158
+ REQUIRE(responses_from_active == 1);
159
+ for (auto& resp : response.entries) {
160
+ REQUIRE_FALSE(resp.cas.empty());
161
+ REQUIRE(resp.fields.size() == 1);
162
+ REQUIRE_FALSE(resp.fields[0].exists);
163
+ REQUIRE(resp.fields[0].path == req.specs[0].path_);
164
+ REQUIRE(resp.fields[0].value.empty());
165
+ REQUIRE(resp.fields[0].status == expected_status);
166
+ REQUIRE(resp.fields[0].ec == expected_ec);
167
+ }
168
+ }
169
+
68
170
  void
69
171
  assert_single_mutate_success(couchbase::core::operations::mutate_in_response resp, const std::string& path, const std::string& value = "")
70
172
  {
@@ -197,6 +299,10 @@ TEST_CASE("integration: subdoc get & exists", "[integration]")
197
299
 
198
300
  SECTION("non json get")
199
301
  {
302
+ if (integration.cluster_version().is_mock()) {
303
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
304
+ "https://github.com/couchbaselabs/gocaves/issues/103");
305
+ }
200
306
  assert_single_lookup_error(integration,
201
307
  non_json_id,
202
308
  couchbase::lookup_in_specs::get("non-exist"),
@@ -206,6 +312,10 @@ TEST_CASE("integration: subdoc get & exists", "[integration]")
206
312
 
207
313
  SECTION("non json exists")
208
314
  {
315
+ if (integration.cluster_version().is_mock()) {
316
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
317
+ "https://github.com/couchbaselabs/gocaves/issues/103");
318
+ }
209
319
  assert_single_lookup_error(integration,
210
320
  non_json_id,
211
321
  couchbase::lookup_in_specs::exists("non-exist"),
@@ -218,11 +328,19 @@ TEST_CASE("integration: subdoc get & exists", "[integration]")
218
328
  {
219
329
  std::vector<std::string> invalid_paths = { "invalid..path", "invalid[-2]" };
220
330
  for (const auto& path : invalid_paths) {
221
- assert_single_lookup_error(integration,
222
- id,
223
- couchbase::lookup_in_specs::get(path),
224
- couchbase::key_value_status_code::subdoc_path_invalid,
225
- couchbase::errc::key_value::path_invalid);
331
+ if (integration.cluster_version().is_mock()) {
332
+ assert_single_lookup_error(integration,
333
+ id,
334
+ couchbase::lookup_in_specs::get(path),
335
+ couchbase::key_value_status_code::subdoc_path_not_found,
336
+ couchbase::errc::key_value::path_not_found);
337
+ } else {
338
+ assert_single_lookup_error(integration,
339
+ id,
340
+ couchbase::lookup_in_specs::get(path),
341
+ couchbase::key_value_status_code::subdoc_path_invalid,
342
+ couchbase::errc::key_value::path_invalid);
343
+ }
226
344
  }
227
345
  }
228
346
 
@@ -317,6 +435,10 @@ TEST_CASE("integration: subdoc store", "[integration]")
317
435
 
318
436
  SECTION("non json")
319
437
  {
438
+ if (integration.cluster_version().is_mock()) {
439
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
440
+ "https://github.com/couchbaselabs/gocaves/issues/103");
441
+ }
320
442
  std::string path{ "dict" };
321
443
  auto value = couchbase::core::utils::to_binary("non-json");
322
444
  couchbase::core::operations::mutate_in_request req{ id };
@@ -411,6 +533,11 @@ TEST_CASE("integration: subdoc mutate in store semantics", "[integration]")
411
533
  TEST_CASE("integration: subdoc unique", "[integration]")
412
534
  {
413
535
  test::utils::integration_test_guard integration;
536
+
537
+ if (integration.cluster_version().is_mock()) {
538
+ SKIP("GOCAVES does not support subdocument create_path feature. See https://github.com/couchbaselabs/gocaves/issues/17");
539
+ }
540
+
414
541
  test::utils::open_bucket(integration.cluster, integration.ctx.bucket);
415
542
  couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("subdoc") };
416
543
 
@@ -453,7 +580,6 @@ TEST_CASE("integration: subdoc unique", "[integration]")
453
580
  couchbase::mutate_in_specs{ couchbase::mutate_in_specs::array_append("a", tao::json::empty_object).create_path() }.specs();
454
581
  auto resp = test::utils::execute(integration.cluster, req);
455
582
  assert_single_mutate_success(resp, "a");
456
- assert_single_lookup_success(integration, id, couchbase::lookup_in_specs::get("a[-1]"), "{}");
457
583
  }
458
584
 
459
585
  {
@@ -472,7 +598,10 @@ TEST_CASE("integration: subdoc counter", "[integration]")
472
598
  couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("subdoc") };
473
599
 
474
600
  {
475
- auto value_json = couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
601
+ auto value_json =
602
+ integration.cluster_version().is_mock() // kv_engine creates counters automatically
603
+ ? couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]],"counter":0})")
604
+ : couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
476
605
  couchbase::core::operations::insert_request req{ id, value_json };
477
606
  auto resp = test::utils::execute(integration.cluster, req);
478
607
  REQUIRE_SUCCESS(resp.ctx.ec());
@@ -497,6 +626,9 @@ TEST_CASE("integration: subdoc counter", "[integration]")
497
626
 
498
627
  SECTION("max value")
499
628
  {
629
+ if (integration.cluster_version().is_mock()) {
630
+ SKIP("GOCAVES incorrectly handles limits for subdoc counters. See https://github.com/couchbaselabs/gocaves/issues/104");
631
+ }
500
632
  {
501
633
  int64_t max_value = std::numeric_limits<int64_t>::max();
502
634
  couchbase::core::operations::mutate_in_request req{ id };
@@ -516,6 +648,9 @@ TEST_CASE("integration: subdoc counter", "[integration]")
516
648
 
517
649
  SECTION("invalid delta")
518
650
  {
651
+ if (integration.cluster_version().is_mock()) {
652
+ SKIP("GOCAVES incorrectly handles zero delta for subdoc counters. See https://github.com/couchbaselabs/gocaves/issues/105");
653
+ }
519
654
  couchbase::core::operations::mutate_in_request req{ id };
520
655
  req.specs = couchbase::mutate_in_specs{ couchbase::mutate_in_specs::increment("counter", 0) }.specs();
521
656
  auto resp = test::utils::execute(integration.cluster, req);
@@ -525,6 +660,9 @@ TEST_CASE("integration: subdoc counter", "[integration]")
525
660
 
526
661
  SECTION("increase number already too big")
527
662
  {
663
+ if (integration.cluster_version().is_mock()) {
664
+ SKIP("GOCAVES incorrectly handles big values for subdoc counters. See https://github.com/couchbaselabs/gocaves/issues/106");
665
+ }
528
666
  {
529
667
  auto big_value = R"({"counter":)" + std::to_string(std::numeric_limits<int64_t>::max()) + "999999999999999999999999999999}";
530
668
  auto value_json = couchbase::core::utils::to_binary(big_value);
@@ -621,7 +759,11 @@ TEST_CASE("integration: subdoc multi lookup", "[integration]")
621
759
  }
622
760
  .specs();
623
761
  auto resp = test::utils::execute(integration.cluster, req);
624
- REQUIRE(resp.ctx.ec() == couchbase::errc::common::invalid_argument);
762
+ if (integration.cluster_version().is_mock()) {
763
+ REQUIRE(resp.ctx.ec() == couchbase::errc::common::unsupported_operation);
764
+ } else {
765
+ REQUIRE(resp.ctx.ec() == couchbase::errc::common::invalid_argument);
766
+ }
625
767
  }
626
768
 
627
769
  SECTION("missing key")
@@ -647,7 +789,10 @@ TEST_CASE("integration: subdoc multi mutation", "[integration]")
647
789
  couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("subdoc") };
648
790
 
649
791
  {
650
- auto value_json = couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
792
+ auto value_json =
793
+ integration.cluster_version().is_mock() // kv_engine creates counters automatically
794
+ ? couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]],"counter":0})")
795
+ : couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
651
796
  couchbase::core::operations::insert_request req{ id, value_json };
652
797
  auto resp = test::utils::execute(integration.cluster, req);
653
798
  REQUIRE_SUCCESS(resp.ctx.ec());
@@ -676,6 +821,9 @@ TEST_CASE("integration: subdoc multi mutation", "[integration]")
676
821
 
677
822
  SECTION("replace with errors")
678
823
  {
824
+ if (integration.cluster_version().is_mock()) {
825
+ SKIP("GOCAVES incorrectly uses error indexes for subdoc mutations. See https://github.com/couchbaselabs/gocaves/issues/107");
826
+ }
679
827
  couchbase::core::operations::mutate_in_request req{ id };
680
828
  req.specs =
681
829
  couchbase::mutate_in_specs{
@@ -695,6 +843,11 @@ TEST_CASE("integration: subdoc multi mutation", "[integration]")
695
843
  TEST_CASE("integration: subdoc expiry")
696
844
  {
697
845
  test::utils::integration_test_guard integration;
846
+
847
+ if (integration.cluster_version().is_mock()) {
848
+ SKIP("GOCAVES does not support subdoc mutations with expiry. See https://github.com/couchbaselabs/gocaves/issues/85");
849
+ }
850
+
698
851
  test::utils::open_bucket(integration.cluster, integration.ctx.bucket);
699
852
  couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("subdoc") };
700
853
 
@@ -922,3 +1075,556 @@ TEST_CASE("integration: subdoc top level array", "[integration]")
922
1075
  REQUIRE(resp.fields[0].value == couchbase::core::utils::to_binary("3"));
923
1076
  }
924
1077
  }
1078
+
1079
+ TEST_CASE("integration: subdoc all replica reads", "[integration]")
1080
+ {
1081
+
1082
+ test::utils::integration_test_guard integration;
1083
+
1084
+ if (!integration.has_bucket_capability("subdoc.ReplicaRead")) {
1085
+ SKIP("cluster does not support replica_read");
1086
+ }
1087
+
1088
+ auto number_of_replicas = integration.number_of_replicas();
1089
+
1090
+ if (number_of_replicas == 0) {
1091
+ SKIP("bucket has zero replicas");
1092
+ }
1093
+ if (integration.number_of_nodes() <= number_of_replicas) {
1094
+ SKIP(fmt::format("number of nodes ({}) is less or equal to number of replicas ({})",
1095
+ integration.number_of_nodes(),
1096
+ integration.number_of_replicas()));
1097
+ }
1098
+
1099
+ auto key = test::utils::uniq_id("lookup_in_any_replica");
1100
+ couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", key };
1101
+
1102
+ {
1103
+ auto value_json = couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
1104
+ couchbase::core::operations::insert_request req{ id, value_json };
1105
+ req.durability_level = couchbase::durability_level::majority_and_persist_to_active;
1106
+ auto resp = test::utils::execute(integration.cluster, req);
1107
+ REQUIRE_SUCCESS(resp.ctx.ec());
1108
+ }
1109
+
1110
+ SECTION("dict get")
1111
+ {
1112
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::get("dictkey"), R"("dictval")");
1113
+ }
1114
+
1115
+ SECTION("dict exists")
1116
+ {
1117
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::exists("dictkey"));
1118
+ }
1119
+
1120
+ SECTION("array get")
1121
+ {
1122
+ assert_single_lookup_all_replica_success(
1123
+ integration, id, couchbase::lookup_in_specs::get("array"), "[1,2,3,4,[10,20,30,[100,200,300]]]");
1124
+ }
1125
+
1126
+ SECTION("array exists")
1127
+ {
1128
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::exists("array"));
1129
+ }
1130
+
1131
+ SECTION("array index get")
1132
+ {
1133
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::get("array[0]"), "1");
1134
+ }
1135
+
1136
+ SECTION("array index exists")
1137
+ {
1138
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::exists("array[0]"));
1139
+ }
1140
+
1141
+ SECTION("non existent path get")
1142
+ {
1143
+ assert_single_lookup_all_replica_error(integration,
1144
+ id,
1145
+ couchbase::lookup_in_specs::get("non-exist"),
1146
+ couchbase::key_value_status_code::subdoc_path_not_found,
1147
+ couchbase::errc::key_value::path_not_found);
1148
+ }
1149
+
1150
+ SECTION("non existent path exists")
1151
+ {
1152
+ assert_single_lookup_all_replica_error(integration,
1153
+ id,
1154
+ couchbase::lookup_in_specs::exists("non-exist"),
1155
+ couchbase::key_value_status_code::subdoc_path_not_found,
1156
+ couchbase::errc::key_value::path_not_found);
1157
+ }
1158
+
1159
+ SECTION("non existent doc")
1160
+ {
1161
+ couchbase::core::document_id missing_id{ integration.ctx.bucket, "_default", "_default", "missing_key" };
1162
+
1163
+ SECTION("non existent doc get")
1164
+ {
1165
+ couchbase::core::operations::lookup_in_all_replicas_request req{ missing_id };
1166
+ req.specs =
1167
+ couchbase::lookup_in_specs{
1168
+ couchbase::lookup_in_specs::get("non-exist"),
1169
+ }
1170
+ .specs();
1171
+ auto resp = test::utils::execute(integration.cluster, req);
1172
+ REQUIRE(resp.ctx.ec() == couchbase::errc::key_value::document_not_found);
1173
+ REQUIRE(resp.entries.empty());
1174
+ }
1175
+
1176
+ SECTION("non existent doc exists")
1177
+ {
1178
+ couchbase::core::operations::lookup_in_all_replicas_request req{ missing_id };
1179
+ req.specs =
1180
+ couchbase::lookup_in_specs{
1181
+ couchbase::lookup_in_specs::exists("non-exist"),
1182
+ }
1183
+ .specs();
1184
+ auto resp = test::utils::execute(integration.cluster, req);
1185
+ REQUIRE(resp.ctx.ec() == couchbase::errc::key_value::document_not_found);
1186
+ REQUIRE(resp.entries.empty());
1187
+ }
1188
+ }
1189
+
1190
+ SECTION("non json")
1191
+ {
1192
+ couchbase::core::document_id non_json_id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("non_json") };
1193
+ auto non_json_doc = couchbase::core::utils::to_binary("string");
1194
+
1195
+ {
1196
+ couchbase::core::operations::insert_request req{ non_json_id, non_json_doc };
1197
+ auto resp = test::utils::execute(integration.cluster, req);
1198
+ REQUIRE_SUCCESS(resp.ctx.ec());
1199
+ }
1200
+
1201
+ SECTION("non json get")
1202
+ {
1203
+ if (integration.cluster_version().is_mock()) {
1204
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
1205
+ "https://github.com/couchbaselabs/gocaves/issues/103");
1206
+ }
1207
+ assert_single_lookup_all_replica_error(integration,
1208
+ non_json_id,
1209
+ couchbase::lookup_in_specs::get("non-exist"),
1210
+ couchbase::key_value_status_code::subdoc_doc_not_json,
1211
+ couchbase::errc::key_value::document_not_json);
1212
+ }
1213
+
1214
+ SECTION("non json exists")
1215
+ {
1216
+ if (integration.cluster_version().is_mock()) {
1217
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
1218
+ "https://github.com/couchbaselabs/gocaves/issues/103");
1219
+ }
1220
+ assert_single_lookup_all_replica_error(integration,
1221
+ non_json_id,
1222
+ couchbase::lookup_in_specs::exists("non-exist"),
1223
+ couchbase::key_value_status_code::subdoc_doc_not_json,
1224
+ couchbase::errc::key_value::document_not_json);
1225
+ }
1226
+ }
1227
+
1228
+ SECTION("invalid path")
1229
+ {
1230
+ std::vector<std::string> invalid_paths = { "invalid..path", "invalid[-2]" };
1231
+ for (const auto& path : invalid_paths) {
1232
+ if (integration.cluster_version().is_mock()) {
1233
+ assert_single_lookup_all_replica_error(integration,
1234
+ id,
1235
+ couchbase::lookup_in_specs::get(path),
1236
+ couchbase::key_value_status_code::subdoc_path_not_found,
1237
+ couchbase::errc::key_value::path_not_found);
1238
+ } else {
1239
+ assert_single_lookup_all_replica_error(integration,
1240
+ id,
1241
+ couchbase::lookup_in_specs::get(path),
1242
+ couchbase::key_value_status_code::subdoc_path_invalid,
1243
+ couchbase::errc::key_value::path_invalid);
1244
+ }
1245
+ }
1246
+ }
1247
+
1248
+ SECTION("negative paths")
1249
+ {
1250
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::get("array[-1][-1][-1]"), "300");
1251
+ }
1252
+
1253
+ SECTION("nested arrays")
1254
+ {
1255
+ assert_single_lookup_all_replica_success(integration, id, couchbase::lookup_in_specs::get("array[4][3][2]"), "300");
1256
+ }
1257
+
1258
+ SECTION("path mismatch")
1259
+ {
1260
+ assert_single_lookup_all_replica_error(integration,
1261
+ id,
1262
+ couchbase::lookup_in_specs::get("array.key"),
1263
+ couchbase::key_value_status_code::subdoc_path_mismatch,
1264
+ couchbase::errc::key_value::path_mismatch);
1265
+ }
1266
+
1267
+ SECTION("public API")
1268
+ {
1269
+ auto collection = couchbase::cluster(integration.cluster).bucket(integration.ctx.bucket).scope("_default").collection("_default");
1270
+
1271
+ SECTION("lookup in all replicas")
1272
+ {
1273
+ auto specs = couchbase::lookup_in_specs{ couchbase::lookup_in_specs::get("dictkey"),
1274
+ couchbase::lookup_in_specs::exists("array"),
1275
+ couchbase::lookup_in_specs::count("array") };
1276
+ auto [ctx, result] = collection.lookup_in_all_replicas(key, specs).get();
1277
+ REQUIRE_SUCCESS(ctx.ec());
1278
+ REQUIRE(result.size() == number_of_replicas + 1);
1279
+ auto responses_from_active = std::count_if(result.begin(), result.end(), [](const auto& r) { return !r.is_replica(); });
1280
+ REQUIRE(responses_from_active == 1);
1281
+ for (auto& res : result) {
1282
+ REQUIRE(!res.cas().empty());
1283
+ REQUIRE("dictval" == res.content_as<std::string>(0));
1284
+ REQUIRE(res.exists("array"));
1285
+ REQUIRE(5 == res.content_as<int>(2));
1286
+ }
1287
+ }
1288
+
1289
+ SECTION("missing document")
1290
+ {
1291
+ auto specs = couchbase::lookup_in_specs{
1292
+ couchbase::lookup_in_specs::get("non-exists"),
1293
+ };
1294
+ auto [ctx, result] = collection.lookup_in_all_replicas("missing-key", specs).get();
1295
+ REQUIRE(ctx.ec() == couchbase::errc::key_value::document_not_found);
1296
+ REQUIRE(result.empty());
1297
+ }
1298
+ }
1299
+ }
1300
+
1301
+ TEST_CASE("integration: subdoc any replica reads", "[integration]")
1302
+ {
1303
+ test::utils::integration_test_guard integration;
1304
+
1305
+ if (!integration.has_bucket_capability("subdoc.ReplicaRead")) {
1306
+ SKIP("cluster does not support replica_read");
1307
+ }
1308
+
1309
+ auto number_of_replicas = integration.number_of_replicas();
1310
+
1311
+ if (number_of_replicas == 0) {
1312
+ SKIP("bucket has zero replicas");
1313
+ }
1314
+ if (integration.number_of_nodes() <= number_of_replicas) {
1315
+ SKIP(fmt::format("number of nodes ({}) is less or equal to number of replicas ({})",
1316
+ integration.number_of_nodes(),
1317
+ integration.number_of_replicas()));
1318
+ }
1319
+
1320
+ test::utils::open_bucket(integration.cluster, integration.ctx.bucket);
1321
+
1322
+ auto key = test::utils::uniq_id("lookup_in_any_replica");
1323
+ couchbase::core::document_id id{ integration.ctx.bucket, "_default", "_default", key };
1324
+
1325
+ {
1326
+ auto value_json = couchbase::core::utils::to_binary(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
1327
+ couchbase::core::operations::insert_request req{ id, value_json };
1328
+ req.durability_level = couchbase::durability_level::majority_and_persist_to_active;
1329
+ auto resp = test::utils::execute(integration.cluster, req);
1330
+ REQUIRE_SUCCESS(resp.ctx.ec());
1331
+ }
1332
+
1333
+ SECTION("dict get")
1334
+ {
1335
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::get("dictkey"), R"("dictval")");
1336
+ }
1337
+
1338
+ SECTION("dict exists")
1339
+ {
1340
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::exists("dictkey"));
1341
+ }
1342
+
1343
+ SECTION("array get")
1344
+ {
1345
+ assert_single_lookup_any_replica_success(
1346
+ integration, id, couchbase::lookup_in_specs::get("array"), "[1,2,3,4,[10,20,30,[100,200,300]]]");
1347
+ }
1348
+
1349
+ SECTION("array exists")
1350
+ {
1351
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::exists("array"));
1352
+ }
1353
+
1354
+ SECTION("array index get")
1355
+ {
1356
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::get("array[0]"), "1");
1357
+ }
1358
+
1359
+ SECTION("array index exists")
1360
+ {
1361
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::exists("array[0]"));
1362
+ }
1363
+
1364
+ SECTION("non existent path get")
1365
+ {
1366
+ assert_single_lookup_any_replica_error(integration,
1367
+ id,
1368
+ couchbase::lookup_in_specs::get("non-exist"),
1369
+ couchbase::key_value_status_code::subdoc_path_not_found,
1370
+ couchbase::errc::key_value::path_not_found);
1371
+ }
1372
+
1373
+ SECTION("non existent path exists")
1374
+ {
1375
+ assert_single_lookup_any_replica_error(integration,
1376
+ id,
1377
+ couchbase::lookup_in_specs::exists("non-exist"),
1378
+ couchbase::key_value_status_code::subdoc_path_not_found,
1379
+ couchbase::errc::key_value::path_not_found);
1380
+ }
1381
+
1382
+ SECTION("non existent doc")
1383
+ {
1384
+ couchbase::core::document_id missing_id{ integration.ctx.bucket, "_default", "_default", "missing_key" };
1385
+
1386
+ SECTION("non existent doc get")
1387
+ {
1388
+ couchbase::core::operations::lookup_in_any_replica_request req{ missing_id };
1389
+ req.specs =
1390
+ couchbase::lookup_in_specs{
1391
+ couchbase::lookup_in_specs::get("non-exist"),
1392
+ }
1393
+ .specs();
1394
+ auto resp = test::utils::execute(integration.cluster, req);
1395
+ REQUIRE(resp.ctx.ec() == couchbase::errc::key_value::document_irretrievable);
1396
+ REQUIRE(resp.fields.empty());
1397
+ }
1398
+
1399
+ SECTION("non existent doc exists")
1400
+ {
1401
+ couchbase::core::operations::lookup_in_any_replica_request req{ missing_id };
1402
+ req.specs =
1403
+ couchbase::lookup_in_specs{
1404
+ couchbase::lookup_in_specs::exists("non-exist"),
1405
+ }
1406
+ .specs();
1407
+ auto resp = test::utils::execute(integration.cluster, req);
1408
+ REQUIRE(resp.ctx.ec() == couchbase::errc::key_value::document_irretrievable);
1409
+ REQUIRE(resp.fields.empty());
1410
+ }
1411
+ }
1412
+
1413
+ SECTION("non json")
1414
+ {
1415
+ couchbase::core::document_id non_json_id{ integration.ctx.bucket, "_default", "_default", test::utils::uniq_id("non_json") };
1416
+ auto non_json_doc = couchbase::core::utils::to_binary("string");
1417
+
1418
+ {
1419
+ couchbase::core::operations::insert_request req{ non_json_id, non_json_doc };
1420
+ auto resp = test::utils::execute(integration.cluster, req);
1421
+ REQUIRE_SUCCESS(resp.ctx.ec());
1422
+ }
1423
+
1424
+ SECTION("non json get")
1425
+ {
1426
+ if (integration.cluster_version().is_mock()) {
1427
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
1428
+ "https://github.com/couchbaselabs/gocaves/issues/103");
1429
+ }
1430
+ assert_single_lookup_any_replica_error(integration,
1431
+ non_json_id,
1432
+ couchbase::lookup_in_specs::get("non-exist"),
1433
+ couchbase::key_value_status_code::subdoc_doc_not_json,
1434
+ couchbase::errc::key_value::document_not_json);
1435
+ }
1436
+
1437
+ SECTION("non json exists")
1438
+ {
1439
+ if (integration.cluster_version().is_mock()) {
1440
+ SKIP("GOCAVES does not handle subdocument operations for non-JSON documents. See "
1441
+ "https://github.com/couchbaselabs/gocaves/issues/103");
1442
+ }
1443
+ assert_single_lookup_any_replica_error(integration,
1444
+ non_json_id,
1445
+ couchbase::lookup_in_specs::exists("non-exist"),
1446
+ couchbase::key_value_status_code::subdoc_doc_not_json,
1447
+ couchbase::errc::key_value::document_not_json);
1448
+ }
1449
+ }
1450
+
1451
+ SECTION("invalid path")
1452
+ {
1453
+ std::vector<std::string> invalid_paths = { "invalid..path", "invalid[-2]" };
1454
+ for (const auto& path : invalid_paths) {
1455
+ if (integration.cluster_version().is_mock()) {
1456
+ assert_single_lookup_any_replica_error(integration,
1457
+ id,
1458
+ couchbase::lookup_in_specs::get(path),
1459
+ couchbase::key_value_status_code::subdoc_path_not_found,
1460
+ couchbase::errc::key_value::path_not_found);
1461
+ } else {
1462
+ assert_single_lookup_any_replica_error(integration,
1463
+ id,
1464
+ couchbase::lookup_in_specs::get(path),
1465
+ couchbase::key_value_status_code::subdoc_path_invalid,
1466
+ couchbase::errc::key_value::path_invalid);
1467
+ }
1468
+ }
1469
+ }
1470
+
1471
+ SECTION("negative paths")
1472
+ {
1473
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::get("array[-1][-1][-1]"), "300");
1474
+ }
1475
+
1476
+ SECTION("nested arrays")
1477
+ {
1478
+ assert_single_lookup_any_replica_success(integration, id, couchbase::lookup_in_specs::get("array[4][3][2]"), "300");
1479
+ }
1480
+
1481
+ SECTION("path mismatch")
1482
+ {
1483
+ assert_single_lookup_any_replica_error(integration,
1484
+ id,
1485
+ couchbase::lookup_in_specs::get("array.key"),
1486
+ couchbase::key_value_status_code::subdoc_path_mismatch,
1487
+ couchbase::errc::key_value::path_mismatch);
1488
+ }
1489
+
1490
+ SECTION("too many specs")
1491
+ {
1492
+ couchbase::core::operations::lookup_in_any_replica_request req{ id };
1493
+ auto specs = couchbase::lookup_in_specs{};
1494
+
1495
+ for (int i = 0; i < 17; i++) {
1496
+ specs.push_back(couchbase::lookup_in_specs::get("dictkey"));
1497
+ }
1498
+ req.specs = specs.specs();
1499
+
1500
+ auto resp = test::utils::execute(integration.cluster, req);
1501
+ REQUIRE(resp.ctx.ec() == couchbase::errc::common::invalid_argument);
1502
+ REQUIRE(resp.fields.empty());
1503
+ }
1504
+
1505
+ SECTION("public API")
1506
+ {
1507
+ auto collection = couchbase::cluster(integration.cluster).bucket(integration.ctx.bucket).scope("_default").collection("_default");
1508
+
1509
+ SECTION("lookup in any replica")
1510
+ {
1511
+ auto specs = couchbase::lookup_in_specs{ couchbase::lookup_in_specs::get("dictkey"),
1512
+ couchbase::lookup_in_specs::exists("array"),
1513
+ couchbase::lookup_in_specs::count("array") };
1514
+ auto [ctx, result] = collection.lookup_in_any_replica(key, specs).get();
1515
+ REQUIRE_SUCCESS(ctx.ec());
1516
+ REQUIRE(!result.cas().empty());
1517
+ REQUIRE("dictval" == result.content_as<std::string>(0));
1518
+ REQUIRE(result.exists("array"));
1519
+ REQUIRE(5 == result.content_as<int>(2));
1520
+ }
1521
+
1522
+ SECTION("missing document")
1523
+ {
1524
+ auto specs = couchbase::lookup_in_specs{
1525
+ couchbase::lookup_in_specs::get("non-exists"),
1526
+ };
1527
+ auto [ctx, result] = collection.lookup_in_any_replica("missing-key", specs).get();
1528
+ REQUIRE(ctx.ec() == couchbase::errc::key_value::document_irretrievable);
1529
+ REQUIRE(result.cas().empty());
1530
+ }
1531
+
1532
+ SECTION("too many specs")
1533
+ {
1534
+ auto specs = couchbase::lookup_in_specs{};
1535
+
1536
+ for (int i = 0; i < 17; i++) {
1537
+ specs.push_back(couchbase::lookup_in_specs::get("dictkey"));
1538
+ }
1539
+ auto [ctx, result] = collection.lookup_in_any_replica(key, specs).get();
1540
+ REQUIRE(ctx.ec() == couchbase::errc::common::invalid_argument);
1541
+ REQUIRE(result.cas().empty());
1542
+ }
1543
+ }
1544
+ }
1545
+
1546
+ TEST_CASE("integration: public API lookup in per-spec errors", "[integration]")
1547
+ {
1548
+ test::utils::integration_test_guard integration;
1549
+
1550
+ auto collection = couchbase::cluster(integration.cluster).bucket(integration.ctx.bucket).scope("_default").collection("_default");
1551
+
1552
+ auto key = test::utils::uniq_id("lookup_in_path_invalid");
1553
+ {
1554
+ auto value_json = couchbase::core::utils::json::parse(R"({"dictkey":"dictval","array":[1,2,3,4,[10,20,30,[100,200,300]]]})");
1555
+ auto [ctx, result] = collection.upsert(key, value_json).get();
1556
+ REQUIRE_SUCCESS(ctx.ec());
1557
+ }
1558
+
1559
+ SECTION("path invalid")
1560
+ {
1561
+ auto specs = couchbase::lookup_in_specs{
1562
+ couchbase::lookup_in_specs::get("..dictkey"),
1563
+ };
1564
+ auto [ctx, result] = collection.lookup_in(key, specs).get();
1565
+ std::error_code ec{};
1566
+ try {
1567
+ std::ignore = result.content_as<std::string>(0);
1568
+ } catch (std::system_error& exc) {
1569
+ ec = exc.code();
1570
+ }
1571
+ REQUIRE(ec == couchbase::errc::key_value::path_invalid);
1572
+
1573
+ ec.clear();
1574
+ try {
1575
+ std::ignore = result.exists(0);
1576
+ } catch (std::system_error& exc) {
1577
+ ec = exc.code();
1578
+ }
1579
+ REQUIRE(ec == couchbase::errc::key_value::path_invalid);
1580
+ }
1581
+
1582
+ SECTION("path mismatch")
1583
+ {
1584
+ auto specs = couchbase::lookup_in_specs{
1585
+ couchbase::lookup_in_specs::count("dictkey"),
1586
+ };
1587
+ auto [ctx, result] = collection.lookup_in(key, specs).get();
1588
+
1589
+ std::error_code ec{};
1590
+ try {
1591
+ std::ignore = result.content_as<std::string>(0);
1592
+ } catch (std::system_error& exc) {
1593
+ ec = exc.code();
1594
+ }
1595
+ REQUIRE(ec == couchbase::errc::key_value::path_mismatch);
1596
+
1597
+ ec.clear();
1598
+ try {
1599
+ std::ignore = result.exists(0);
1600
+ } catch (std::system_error& exc) {
1601
+ ec = exc.code();
1602
+ }
1603
+ REQUIRE(ec == couchbase::errc::key_value::path_mismatch);
1604
+ }
1605
+
1606
+ SECTION("path not found")
1607
+ {
1608
+ auto specs = couchbase::lookup_in_specs{
1609
+ couchbase::lookup_in_specs::get("dictkey2"),
1610
+ };
1611
+ auto [ctx, result] = collection.lookup_in(key, specs).get();
1612
+
1613
+ std::error_code ec{};
1614
+ try {
1615
+ std::ignore = result.content_as<std::string>(0);
1616
+ } catch (std::system_error& exc) {
1617
+ ec = exc.code();
1618
+ }
1619
+ REQUIRE(ec == couchbase::errc::key_value::path_not_found);
1620
+
1621
+ ec.clear();
1622
+ try {
1623
+ auto exists = result.exists(0);
1624
+ REQUIRE_FALSE(exists);
1625
+ } catch (std::system_error& exc) {
1626
+ ec = exc.code();
1627
+ }
1628
+ REQUIRE_SUCCESS(ec);
1629
+ }
1630
+ }