couchbase 3.4.2 → 3.4.4

Sign up to get free protection for your applications and to get access to all the features.
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
+ }