couchbase 3.4.0 → 3.4.2

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/ext/couchbase/CMakeLists.txt +10 -3
  4. data/ext/couchbase/cmake/CompilerWarnings.cmake +12 -4
  5. data/ext/couchbase/cmake/Documentation.cmake +4 -3
  6. data/ext/couchbase/cmake/OpenSSL.cmake +52 -7
  7. data/ext/couchbase/cmake/ThirdPartyDependencies.cmake +4 -0
  8. data/ext/couchbase/cmake/VersionInfo.cmake +39 -3
  9. data/ext/couchbase/cmake/test_openssl.cxx +7 -0
  10. data/ext/couchbase/core/cluster_options.hxx +0 -1
  11. data/ext/couchbase/core/config_profile.cxx +23 -1
  12. data/ext/couchbase/core/config_profile.hxx +2 -12
  13. data/ext/couchbase/core/crypto/CMakeLists.txt +5 -1
  14. data/ext/couchbase/core/impl/analytics.cxx +236 -0
  15. data/ext/couchbase/core/impl/cluster.cxx +0 -1
  16. data/ext/couchbase/core/impl/collection_query_index_manager.cxx +3 -3
  17. data/ext/couchbase/core/impl/dns_srv_tracker.cxx +5 -3
  18. data/ext/couchbase/core/impl/get_all_query_indexes.cxx +3 -3
  19. data/ext/couchbase/core/impl/query.cxx +5 -5
  20. data/ext/couchbase/core/impl/transaction_get_result.cxx +54 -0
  21. data/ext/couchbase/core/io/dns_client.cxx +225 -0
  22. data/ext/couchbase/core/io/dns_client.hxx +19 -188
  23. data/ext/couchbase/core/meta/CMakeLists.txt +7 -5
  24. data/ext/couchbase/core/meta/version.cxx +19 -0
  25. data/ext/couchbase/core/operations/document_search.cxx +5 -2
  26. data/ext/couchbase/core/operations/document_search.hxx +0 -1
  27. data/ext/couchbase/core/transactions/active_transaction_record.hxx +2 -2
  28. data/ext/couchbase/core/transactions/atr_cleanup_entry.cxx +1 -0
  29. data/ext/couchbase/core/transactions/attempt_context_impl.cxx +65 -31
  30. data/ext/couchbase/core/transactions/attempt_context_impl.hxx +44 -23
  31. data/ext/couchbase/core/transactions/forward_compat.hxx +2 -2
  32. data/ext/couchbase/core/transactions/internal/transaction_context.hxx +13 -13
  33. data/ext/couchbase/core/transactions/internal/transaction_fields.hxx +1 -0
  34. data/ext/couchbase/core/transactions/internal/transactions_cleanup.hxx +7 -1
  35. data/ext/couchbase/core/transactions/staged_mutation.cxx +1 -1
  36. data/ext/couchbase/core/transactions/staged_mutation.hxx +12 -2
  37. data/ext/couchbase/core/transactions/transaction_context.cxx +9 -11
  38. data/ext/couchbase/core/transactions/transaction_get_result.cxx +41 -31
  39. data/ext/couchbase/core/transactions/transaction_get_result.hxx +7 -3
  40. data/ext/couchbase/core/transactions/transaction_links.hxx +13 -1
  41. data/ext/couchbase/core/transactions/transactions_cleanup.cxx +144 -155
  42. data/ext/couchbase/core/transactions/waitable_op_list.hxx +1 -0
  43. data/ext/couchbase/core/utils/connection_string.cxx +10 -3
  44. data/ext/couchbase/core/utils/connection_string.hxx +3 -3
  45. data/ext/couchbase/couchbase/analytics_error_context.hxx +143 -0
  46. data/ext/couchbase/couchbase/analytics_meta_data.hxx +155 -0
  47. data/ext/couchbase/couchbase/analytics_metrics.hxx +163 -0
  48. data/ext/couchbase/couchbase/analytics_options.hxx +359 -0
  49. data/ext/couchbase/couchbase/analytics_result.hxx +102 -0
  50. data/ext/couchbase/couchbase/analytics_scan_consistency.hxx +46 -0
  51. data/ext/couchbase/couchbase/analytics_status.hxx +41 -0
  52. data/ext/couchbase/couchbase/analytics_warning.hxx +85 -0
  53. data/ext/couchbase/couchbase/cluster.hxx +35 -2
  54. data/ext/couchbase/couchbase/cluster_options.hxx +10 -10
  55. data/ext/couchbase/couchbase/collection.hxx +22 -17
  56. data/ext/couchbase/couchbase/collection_query_index_manager.hxx +1 -1
  57. data/ext/couchbase/couchbase/common_options.hxx +1 -1
  58. data/ext/couchbase/couchbase/configuration_profile.hxx +1 -1
  59. data/ext/couchbase/couchbase/configuration_profiles_registry.hxx +0 -1
  60. data/ext/couchbase/couchbase/create_primary_query_index_options.hxx +1 -1
  61. data/ext/couchbase/couchbase/drop_primary_query_index_options.hxx +1 -1
  62. data/ext/couchbase/couchbase/drop_query_index_options.hxx +1 -1
  63. data/ext/couchbase/couchbase/fmt/analytics_status.hxx +76 -0
  64. data/ext/couchbase/couchbase/fmt/cas.hxx +12 -0
  65. data/ext/couchbase/couchbase/fmt/durability_level.hxx +6 -0
  66. data/ext/couchbase/couchbase/fmt/key_value_extended_error_info.hxx +6 -0
  67. data/ext/couchbase/couchbase/fmt/key_value_status_code.hxx +6 -0
  68. data/ext/couchbase/couchbase/fmt/mutation_token.hxx +6 -0
  69. data/ext/couchbase/couchbase/fmt/query_scan_consistency.hxx +6 -0
  70. data/ext/couchbase/couchbase/fmt/query_status.hxx +6 -0
  71. data/ext/couchbase/couchbase/fmt/retry_reason.hxx +6 -0
  72. data/ext/couchbase/couchbase/fmt/tls_verify_mode.hxx +6 -0
  73. data/ext/couchbase/couchbase/get_all_query_indexes_options.hxx +5 -4
  74. data/ext/couchbase/couchbase/query_index_manager.hxx +4 -2
  75. data/ext/couchbase/couchbase/query_options.hxx +0 -1
  76. data/ext/couchbase/couchbase/scope.hxx +34 -1
  77. data/ext/couchbase/couchbase/subdoc/array_add_unique.hxx +2 -0
  78. data/ext/couchbase/couchbase/subdoc/array_append.hxx +2 -0
  79. data/ext/couchbase/couchbase/subdoc/array_insert.hxx +2 -0
  80. data/ext/couchbase/couchbase/subdoc/array_prepend.hxx +2 -0
  81. data/ext/couchbase/couchbase/subdoc/count.hxx +2 -0
  82. data/ext/couchbase/couchbase/subdoc/counter.hxx +2 -0
  83. data/ext/couchbase/couchbase/subdoc/exists.hxx +2 -0
  84. data/ext/couchbase/couchbase/subdoc/get.hxx +2 -0
  85. data/ext/couchbase/couchbase/subdoc/insert.hxx +2 -0
  86. data/ext/couchbase/couchbase/subdoc/remove.hxx +2 -0
  87. data/ext/couchbase/couchbase/subdoc/replace.hxx +3 -1
  88. data/ext/couchbase/couchbase/subdoc/upsert.hxx +2 -0
  89. data/ext/couchbase/couchbase/transaction_op_error_context.hxx +4 -4
  90. data/ext/couchbase/couchbase/transactions/attempt_context.hxx +1 -1
  91. data/ext/couchbase/couchbase/transactions/transaction_get_result.hxx +36 -51
  92. data/ext/couchbase/couchbase/transactions/transactions_config.hxx +1 -1
  93. data/ext/couchbase/test/CMakeLists.txt +3 -2
  94. data/ext/couchbase/test/test_helper.hxx +1 -1
  95. data/ext/couchbase/test/test_integration_analytics.cxx +289 -13
  96. data/ext/couchbase/test/test_integration_crud.cxx +8 -1
  97. data/ext/couchbase/test/test_integration_examples.cxx +182 -0
  98. data/ext/couchbase/test/test_integration_management.cxx +15 -3
  99. data/ext/couchbase/test/test_integration_search.cxx +601 -0
  100. data/ext/couchbase/test/test_transaction_transaction_simple.cxx +73 -0
  101. data/ext/couchbase/test/test_unit_config_profiles.cxx +12 -12
  102. data/ext/couchbase/test/test_unit_connection_string.cxx +35 -0
  103. data/ext/couchbase/test/test_unit_transaction_utils.cxx +76 -19
  104. data/ext/couchbase/third_party/snappy/CMakeLists.txt +150 -27
  105. data/ext/couchbase/third_party/snappy/cmake/config.h.in +28 -24
  106. data/ext/couchbase/third_party/snappy/snappy-internal.h +189 -25
  107. data/ext/couchbase/third_party/snappy/snappy-sinksource.cc +26 -9
  108. data/ext/couchbase/third_party/snappy/snappy-sinksource.h +11 -11
  109. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.cc +1 -1
  110. data/ext/couchbase/third_party/snappy/snappy-stubs-internal.h +227 -308
  111. data/ext/couchbase/third_party/snappy/snappy-stubs-public.h.in +0 -11
  112. data/ext/couchbase/third_party/snappy/snappy.cc +1176 -410
  113. data/ext/couchbase/third_party/snappy/snappy.h +19 -4
  114. data/ext/couchbase.cxx +506 -26
  115. data/ext/extconf.rb +2 -1
  116. data/ext/revisions.rb +3 -2
  117. data/lib/couchbase/binary_collection.rb +4 -4
  118. data/lib/couchbase/cluster.rb +13 -9
  119. data/lib/couchbase/cluster_registry.rb +7 -2
  120. data/lib/couchbase/collection.rb +5 -0
  121. data/lib/couchbase/configuration.rb +3 -4
  122. data/lib/couchbase/errors.rb +10 -0
  123. data/lib/couchbase/management/collection_query_index_manager.rb +183 -0
  124. data/lib/couchbase/management/query_index_manager.rb +35 -3
  125. data/lib/couchbase/management.rb +1 -0
  126. data/lib/couchbase/options.rb +87 -5
  127. data/lib/couchbase/search_options.rb +158 -240
  128. data/lib/couchbase/version.rb +1 -1
  129. metadata +21 -6
  130. data/ext/couchbase/core/CMakeLists.txt +0 -0
@@ -54,7 +54,9 @@ class count
54
54
  }
55
55
 
56
56
  private:
57
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
57
58
  friend couchbase::lookup_in_specs;
59
+ #endif
58
60
 
59
61
  explicit count(std::string path)
60
62
  : path_(std::move(path))
@@ -69,7 +69,9 @@ class counter
69
69
  }
70
70
 
71
71
  private:
72
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
72
73
  friend couchbase::mutate_in_specs;
74
+ #endif
73
75
 
74
76
  counter(std::string path, std::int64_t value)
75
77
  : path_(std::move(path))
@@ -54,7 +54,9 @@ class exists
54
54
  }
55
55
 
56
56
  private:
57
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
57
58
  friend couchbase::lookup_in_specs;
59
+ #endif
58
60
 
59
61
  explicit exists(std::string path)
60
62
  : path_(std::move(path))
@@ -56,7 +56,9 @@ class get
56
56
  }
57
57
 
58
58
  private:
59
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
59
60
  friend couchbase::lookup_in_specs;
61
+ #endif
60
62
 
61
63
  explicit get(std::string path)
62
64
  : path_(std::move(path))
@@ -71,7 +71,9 @@ class insert
71
71
  }
72
72
 
73
73
  private:
74
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
74
75
  friend couchbase::mutate_in_specs;
76
+ #endif
75
77
 
76
78
  insert(std::string path, std::vector<std::byte> value)
77
79
  : path_(std::move(path))
@@ -54,7 +54,9 @@ class remove
54
54
  }
55
55
 
56
56
  private:
57
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
57
58
  friend couchbase::mutate_in_specs;
59
+ #endif
58
60
 
59
61
  explicit remove(std::string path)
60
62
  : path_(std::move(path))
@@ -56,7 +56,9 @@ class replace
56
56
  }
57
57
 
58
58
  private:
59
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
59
60
  friend couchbase::mutate_in_specs;
61
+ #endif
60
62
 
61
63
  replace(std::string path, std::vector<std::byte> value)
62
64
  : path_(std::move(path))
@@ -86,4 +88,4 @@ class replace
86
88
  bool expand_macro_{ false };
87
89
  };
88
90
  } // namespace subdoc
89
- } // namespace couchbase
91
+ } // namespace couchbase
@@ -71,7 +71,9 @@ class upsert
71
71
  }
72
72
 
73
73
  private:
74
+ #ifndef COUCHBASE_CXX_CLIENT_DOXYGEN
74
75
  friend couchbase::mutate_in_specs;
76
+ #endif
75
77
 
76
78
  upsert(std::string path, std::vector<std::byte> value)
77
79
  : path_(std::move(path))
@@ -46,13 +46,13 @@ class transaction_op_error_context
46
46
  }
47
47
 
48
48
  /**
49
- * The error_code associated with this error context. This will always be a @ref transaction_op_error_code
49
+ * The error_code associated with this error context.
50
50
  *
51
51
  * Note that some query errors are not _transaction_ errors, so this error code will be 0, but there will be
52
- * a @ref transaction_op_error_code#cause() with a query_error_context in it. These errors do not rollback a
52
+ * a @ref cause() with a @ref query_error_context in it. These errors do not rollback a
53
53
  * transaction. If you want to roll it back, raise an exception.
54
54
  *
55
- * @return a transaction_op_error_code, if any.
55
+ * @return a error code, if any.
56
56
  */
57
57
  [[nodiscard]] std::error_code ec() const
58
58
  {
@@ -60,7 +60,7 @@ class transaction_op_error_context
60
60
  }
61
61
 
62
62
  /**
63
- * The underlying cause of this error. This can be either a @ref key_value_error_code or a @ref query_error_context.
63
+ * The underlying cause of this error. This can be either a @ref key_value_error_context or a @ref query_error_context.
64
64
  *
65
65
  * @return the error_context associated with the underlying cause of this error.
66
66
  */
@@ -33,7 +33,7 @@ class attempt_context
33
33
  const Content& content)
34
34
  {
35
35
  if constexpr (std::is_same_v<Content, std::vector<std::byte>>) {
36
- return insert_raw(content, id, content);
36
+ return insert_raw(coll, id, content);
37
37
  } else {
38
38
  return insert_raw(coll, id, codec::tao_json_serializer::serialize(content));
39
39
  }
@@ -24,36 +24,31 @@
24
24
  #include <couchbase/result.hxx>
25
25
  #include <couchbase/transaction_op_error_context.hxx>
26
26
 
27
+ // forward declarations...
28
+ namespace couchbase::core::transactions
29
+ {
30
+ class transaction_get_result;
31
+ class transaction_links;
32
+ class document_metadata;
33
+ } // namespace couchbase::core::transactions
34
+
27
35
  namespace couchbase::transactions
28
36
  {
29
37
 
30
- class transaction_get_result : public result
38
+ class transaction_get_result
31
39
  {
32
- protected:
33
- std::string bucket_{};
34
- std::string scope_{};
35
- std::string collection_{};
36
- std::string key_{};
37
- std::vector<std::byte> content_{};
40
+ friend class couchbase::core::transactions::transaction_get_result;
38
41
 
39
- public:
40
- transaction_get_result() = default;
41
-
42
- transaction_get_result(std::string bucket,
43
- std::string scope,
44
- std::string collection,
45
- std::string key,
46
- couchbase::cas cas,
47
- std::vector<std::byte> content)
48
- : result(cas)
49
- , bucket_(std::move(bucket))
50
- , scope_(std::move(scope))
51
- , collection_(std::move(collection))
52
- , key_(std::move(key))
53
- , content_(std::move(content))
42
+ private:
43
+ std::shared_ptr<couchbase::core::transactions::transaction_get_result> base_{};
44
+
45
+ transaction_get_result(std::shared_ptr<couchbase::core::transactions::transaction_get_result> base)
46
+ : base_(base)
54
47
  {
55
48
  }
56
49
 
50
+ public:
51
+ transaction_get_result();
57
52
  /**
58
53
  * Content of the document.
59
54
  *
@@ -62,7 +57,7 @@ class transaction_get_result : public result
62
57
  template<typename Content>
63
58
  [[nodiscard]] Content content() const
64
59
  {
65
- return codec::tao_json_serializer::deserialize<Content>(content_);
60
+ return codec::tao_json_serializer::deserialize<Content>(content());
66
61
  }
67
62
 
68
63
  /**
@@ -70,64 +65,54 @@ class transaction_get_result : public result
70
65
  *
71
66
  * @return content
72
67
  */
73
- [[nodiscard]] const std::vector<std::byte>& content() const
74
- {
75
- return content_;
76
- }
68
+ [[nodiscard]] const std::vector<std::byte>& content() const;
69
+
77
70
  /**
78
71
  * Copy content into document
79
72
  * @param content
80
73
  */
81
- void content(std::vector<std::byte> content)
82
- {
83
- content_ = std::move(content);
84
- }
74
+ void content(std::vector<std::byte> content);
75
+
85
76
  /**
86
77
  * Move content into document
87
78
  *
88
79
  * @param content
89
80
  */
90
- void content(std::vector<std::byte>&& content)
91
- {
92
- content_ = std::move(content);
93
- }
81
+ void content(std::vector<std::byte>&& content);
94
82
 
95
83
  /**
96
84
  * Get document id.
97
85
  *
98
86
  * @return the id of this document.
99
87
  */
100
- [[nodiscard]] const std::string key() const
101
- {
102
- return key_;
103
- }
88
+ [[nodiscard]] const std::string key() const;
104
89
 
105
90
  /**
106
91
  * Get the name of the bucket this document is in.
107
92
  *
108
93
  * @return name of the bucket which contains the document.
109
94
  */
110
- [[nodiscard]] const std::string bucket() const
111
- {
112
- return bucket_;
113
- }
95
+ [[nodiscard]] const std::string bucket() const;
96
+
114
97
  /**
115
98
  * Get the name of the scope this document is in.
116
99
  *
117
100
  * @return name of the scope which contains the document.
118
101
  */
119
- [[nodiscard]] const std::string scope() const
120
- {
121
- return scope_;
122
- }
102
+ [[nodiscard]] const std::string scope() const;
103
+
123
104
  /**
124
105
  * Get the name of the collection this document is in.
125
106
  *
126
107
  * @return name of the collection which contains the document.
127
108
  */
128
- [[nodiscard]] const std::string collection() const
129
- {
130
- return collection_;
131
- }
109
+ [[nodiscard]] const std::string collection() const;
110
+
111
+ /**
112
+ * Get the CAS fot this document
113
+ *
114
+ * @return the CAS of the document.
115
+ */
116
+ [[nodiscard]] const couchbase::cas cas() const;
132
117
  };
133
118
  } // namespace couchbase::transactions
@@ -115,7 +115,7 @@ class transactions_config
115
115
  /**
116
116
  * @brief Set the expiration time for transactions.
117
117
  *
118
- * @param duration desired expiration for transactions. see @expiration_time().
118
+ * @param duration desired expiration for transactions. see @ref expiration_time().
119
119
  * @return reference to this, so calls can be chained.
120
120
  */
121
121
  template<typename T>
@@ -16,6 +16,7 @@ integration_test(tracer)
16
16
  integration_test(meter)
17
17
  integration_test(transcoders)
18
18
  integration_test(range_scan)
19
+ integration_test(search)
19
20
 
20
21
  unit_test(connection_string)
21
22
  unit_test(utils)
@@ -28,8 +29,6 @@ target_link_libraries(test_unit_jsonsl jsonsl)
28
29
 
29
30
  integration_benchmark(get)
30
31
 
31
- add_subdirectory(tools)
32
-
33
32
  transaction_test(transaction_context)
34
33
  transaction_test(transaction_simple)
35
34
  transaction_test(transaction_simple_async)
@@ -39,3 +38,5 @@ transaction_test(transaction_public_async_api)
39
38
  unit_test(transaction_logging)
40
39
  unit_test(transaction_utils)
41
40
  unit_test(waitable_op_list)
41
+
42
+ integration_test(examples)
@@ -21,7 +21,7 @@
21
21
 
22
22
  #include "utils/binary.hxx"
23
23
  #include "utils/test_context.hxx"
24
- #include "utils/uniq_id.hxx"
24
+ #include "utils/test_data.hxx"
25
25
 
26
26
  #include <catch2/catch.hpp>
27
27
 
@@ -17,7 +17,7 @@
17
17
 
18
18
  #include "core/operations/management/analytics.hxx"
19
19
  #include "core/operations/management/collection_create.hxx"
20
- #include "core/operations/management/scope_create.hxx"
20
+ #include "core/operations/management/collections.hxx"
21
21
  #include "test_helper_integration.hxx"
22
22
 
23
23
  TEST_CASE("integration: analytics query")
@@ -78,7 +78,7 @@ TEST_CASE("integration: analytics query")
78
78
  REQUIRE(test::utils::wait_until([&]() {
79
79
  couchbase::core::operations::analytics_request req{};
80
80
  req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = ?)", dataset_name);
81
- req.positional_parameters.emplace_back(couchbase::core::json_string(couchbase::core::utils::json::generate(test_value)));
81
+ req.positional_parameters.emplace_back(couchbase::core::utils::json::generate(test_value));
82
82
  resp = test::utils::execute(integration.cluster, req);
83
83
  return resp.rows.size() == 1;
84
84
  }));
@@ -130,10 +130,30 @@ TEST_CASE("integration: analytics query")
130
130
 
131
131
  SECTION("consistency")
132
132
  {
133
- couchbase::core::operations::analytics_request req{};
134
- req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value);
135
- req.scan_consistency = couchbase::core::analytics_scan_consistency::request_plus;
136
- auto resp = test::utils::execute(integration.cluster, req);
133
+ couchbase::core::operations::analytics_response resp{};
134
+ CHECK(test::utils::wait_until([&]() {
135
+ /*
136
+ * In consistency test, always do fresh mutation
137
+ */
138
+ test_value = test::utils::uniq_id("value");
139
+ value = couchbase::core::utils::json::generate({ { "testkey", test_value } });
140
+ {
141
+ auto id = couchbase::core::document_id(integration.ctx.bucket, "_default", "_default", key);
142
+ couchbase::core::operations::upsert_request req{ id, couchbase::core::utils::to_binary(value) };
143
+ REQUIRE_SUCCESS(test::utils::execute(integration.cluster, req).ctx.ec());
144
+ }
145
+
146
+ couchbase::core::operations::analytics_request req{};
147
+ req.statement = fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value);
148
+ req.scan_consistency = couchbase::core::analytics_scan_consistency::request_plus;
149
+ resp = test::utils::execute(integration.cluster, req);
150
+ /* Analytics might give us code 23027, ignore it here
151
+ *
152
+ * "errors": [{"code": 23027, "msg": "Bucket default on link Default.Local is not connected"} ],
153
+ */
154
+ return resp.ctx.first_error_code != 23027;
155
+ }));
156
+
137
157
  REQUIRE_SUCCESS(resp.ctx.ec);
138
158
  REQUIRE(resp.rows.size() == 1);
139
159
  REQUIRE(resp.rows[0] == value);
@@ -185,13 +205,15 @@ TEST_CASE("integration: analytics scope query")
185
205
  REQUIRE(created);
186
206
  }
187
207
 
188
- {
189
- couchbase::core::operations::analytics_request req{};
190
- req.statement =
191
- fmt::format("ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name);
192
- auto resp = test::utils::execute(integration.cluster, req);
193
- REQUIRE_SUCCESS(resp.ctx.ec);
194
- }
208
+ CHECK(test::utils::wait_until(
209
+ [&]() {
210
+ couchbase::core::operations::analytics_request req{};
211
+ req.statement =
212
+ fmt::format("ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name);
213
+ auto resp = test::utils::execute(integration.cluster, req);
214
+ return !resp.ctx.ec;
215
+ },
216
+ std::chrono::minutes{ 5 }));
195
217
 
196
218
  auto key = test::utils::uniq_id("key");
197
219
  auto test_value = test::utils::uniq_id("value");
@@ -259,3 +281,257 @@ TEST_CASE("unit: analytics query")
259
281
  REQUIRE(http_req.headers.find("analytics-priority") == http_req.headers.end());
260
282
  }
261
283
  }
284
+
285
+ TEST_CASE("integration: public API analytics query")
286
+ {
287
+ test::utils::integration_test_guard integration;
288
+
289
+ if (!integration.cluster_version().supports_analytics()) {
290
+ return;
291
+ }
292
+
293
+ auto cluster = couchbase::cluster(integration.cluster);
294
+ auto bucket = cluster.bucket(integration.ctx.bucket);
295
+ auto collection = bucket.default_collection();
296
+
297
+ auto dataset_name = test::utils::uniq_id("dataset");
298
+
299
+ {
300
+ couchbase::core::operations::management::analytics_dataset_create_request req{};
301
+ req.dataset_name = dataset_name;
302
+ req.bucket_name = integration.ctx.bucket;
303
+ auto resp = test::utils::execute(integration.cluster, req);
304
+ REQUIRE_SUCCESS(resp.ctx.ec);
305
+ }
306
+
307
+ {
308
+ couchbase::core::operations::management::analytics_link_connect_request req{};
309
+ req.force = true;
310
+ auto resp = test::utils::execute(integration.cluster, req);
311
+ REQUIRE_SUCCESS(resp.ctx.ec);
312
+ }
313
+
314
+ auto key = test::utils::uniq_id("key");
315
+ auto test_value = test::utils::uniq_id("value");
316
+ tao::json::value document = {
317
+ { "testkey", test_value },
318
+ };
319
+ {
320
+ auto [ctx, resp] = collection.upsert(key, document).get();
321
+ REQUIRE_SUCCESS(ctx.ec());
322
+ }
323
+
324
+ SECTION("simple query")
325
+ {
326
+ couchbase::analytics_result resp{};
327
+ couchbase::analytics_error_context ctx{};
328
+ CHECK(test::utils::wait_until([&]() {
329
+ std::tie(ctx, resp) =
330
+ cluster.analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value))
331
+ .get();
332
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
333
+ }));
334
+ REQUIRE_SUCCESS(ctx.ec());
335
+ REQUIRE_FALSE(resp.meta_data().request_id().empty());
336
+ REQUIRE_FALSE(resp.meta_data().client_context_id().empty());
337
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::success);
338
+ auto rows = resp.rows_as_json();
339
+ REQUIRE(rows.size() == 1);
340
+ REQUIRE(rows[0] == document);
341
+ }
342
+
343
+ SECTION("positional params")
344
+ {
345
+ couchbase::analytics_result resp{};
346
+ couchbase::analytics_error_context ctx{};
347
+ CHECK(test::utils::wait_until([&]() {
348
+ std::tie(ctx, resp) = cluster
349
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = ?)", dataset_name),
350
+ couchbase::analytics_options{}.positional_parameters(test_value))
351
+ .get();
352
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
353
+ }));
354
+ REQUIRE_SUCCESS(ctx.ec());
355
+ auto rows = resp.rows_as_json();
356
+ REQUIRE(rows.size() == 1);
357
+ REQUIRE(rows[0] == document);
358
+ }
359
+
360
+ SECTION("named params")
361
+ {
362
+ couchbase::analytics_result resp{};
363
+ couchbase::analytics_error_context ctx{};
364
+ CHECK(test::utils::wait_until([&]() {
365
+ std::tie(ctx, resp) =
366
+ cluster
367
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
368
+ couchbase::analytics_options{}.named_parameters(std::pair{ "testkey", test_value }))
369
+ .get();
370
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
371
+ }));
372
+ REQUIRE_SUCCESS(ctx.ec());
373
+ auto rows = resp.rows_as_json();
374
+ REQUIRE(rows.size() == 1);
375
+ REQUIRE(rows[0] == document);
376
+ }
377
+
378
+ SECTION("named params preformatted")
379
+ {
380
+ couchbase::analytics_result resp{};
381
+ couchbase::analytics_error_context ctx{};
382
+ CHECK(test::utils::wait_until([&]() {
383
+ std::tie(ctx, resp) =
384
+ cluster
385
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
386
+ couchbase::analytics_options{}.encoded_named_parameters(
387
+ { { "testkey", couchbase::core::utils::json::generate_binary(test_value) } }))
388
+ .get();
389
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
390
+ }));
391
+ REQUIRE_SUCCESS(ctx.ec());
392
+ auto rows = resp.rows_as_json();
393
+ REQUIRE(rows.size() == 1);
394
+ REQUIRE(rows[0] == document);
395
+ }
396
+
397
+ SECTION("raw")
398
+ {
399
+ couchbase::analytics_result resp{};
400
+ couchbase::analytics_error_context ctx{};
401
+ CHECK(test::utils::wait_until([&]() {
402
+ std::tie(ctx, resp) =
403
+ cluster
404
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = $testkey)", dataset_name),
405
+ couchbase::analytics_options{}.raw("$testkey", test_value))
406
+ .get();
407
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
408
+ }));
409
+ REQUIRE_SUCCESS(ctx.ec());
410
+ auto rows = resp.rows_as_json();
411
+ REQUIRE(rows.size() == 1);
412
+ REQUIRE(rows[0] == document);
413
+ }
414
+
415
+ SECTION("consistency")
416
+ {
417
+ couchbase::analytics_result resp{};
418
+ couchbase::analytics_error_context ctx{};
419
+ CHECK(test::utils::wait_until([&]() {
420
+ /*
421
+ * In consistency test, always do fresh mutation
422
+ */
423
+ test_value = test::utils::uniq_id("value");
424
+ document = {
425
+ { "testkey", test_value },
426
+ };
427
+ {
428
+ auto [ctx2, _] = collection.upsert(key, document).get();
429
+ REQUIRE_SUCCESS(ctx2.ec());
430
+ }
431
+
432
+ std::tie(ctx, resp) =
433
+ cluster
434
+ .analytics_query(fmt::format(R"(SELECT testkey FROM `Default`.`{}` WHERE testkey = "{}")", dataset_name, test_value),
435
+ couchbase::analytics_options{}.scan_consistency(couchbase::analytics_scan_consistency::request_plus))
436
+ .get();
437
+ /* Analytics might give us code 23027, ignore it here
438
+ *
439
+ * "errors": [{"code": 23027, "msg": "Bucket default on link Default.Local is not connected"} ],
440
+ */
441
+ return ctx.first_error_code() != 23027;
442
+ }));
443
+
444
+ REQUIRE_SUCCESS(ctx.ec());
445
+ auto rows = resp.rows_as_json();
446
+ REQUIRE(rows.size() == 1);
447
+ REQUIRE(rows[0] == document);
448
+ }
449
+
450
+ SECTION("readonly")
451
+ {
452
+ auto [ctx, resp] =
453
+ cluster.analytics_query(fmt::format("DROP DATASET Default.`{}`", dataset_name), couchbase::analytics_options{}.readonly(true))
454
+ .get();
455
+
456
+ REQUIRE(ctx.ec() == couchbase::errc::common::internal_server_failure);
457
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::fatal);
458
+ }
459
+
460
+ {
461
+ couchbase::core::operations::management::analytics_dataset_drop_request req{};
462
+ req.dataset_name = dataset_name;
463
+ test::utils::execute(integration.cluster, req);
464
+ }
465
+ }
466
+
467
+ TEST_CASE("integration: public API analytics scope query")
468
+ {
469
+ test::utils::integration_test_guard integration;
470
+
471
+ if (!integration.cluster_version().supports_analytics() || !integration.cluster_version().supports_collections()) {
472
+ return;
473
+ }
474
+
475
+ auto cluster = couchbase::cluster(integration.cluster);
476
+ auto bucket = cluster.bucket(integration.ctx.bucket);
477
+
478
+ auto scope_name = test::utils::uniq_id("scope");
479
+ auto collection_name = test::utils::uniq_id("collection");
480
+
481
+ {
482
+ const couchbase::core::operations::management::scope_create_request req{ integration.ctx.bucket, scope_name };
483
+ auto resp = test::utils::execute(integration.cluster, req);
484
+ REQUIRE_SUCCESS(resp.ctx.ec);
485
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
486
+ REQUIRE(created);
487
+ }
488
+
489
+ {
490
+ const couchbase::core::operations::management::collection_create_request req{ integration.ctx.bucket, scope_name, collection_name };
491
+ auto resp = test::utils::execute(integration.cluster, req);
492
+ REQUIRE_SUCCESS(resp.ctx.ec);
493
+ auto created = test::utils::wait_until_collection_manifest_propagated(integration.cluster, integration.ctx.bucket, resp.uid);
494
+ REQUIRE(created);
495
+ }
496
+
497
+ CHECK(test::utils::wait_until(
498
+ [&]() {
499
+ auto [ctx, resp] = cluster
500
+ .analytics_query(fmt::format(
501
+ "ALTER COLLECTION `{}`.`{}`.`{}` ENABLE ANALYTICS", integration.ctx.bucket, scope_name, collection_name))
502
+ .get();
503
+ return !ctx.ec();
504
+ },
505
+ std::chrono::minutes{ 5 }));
506
+
507
+ auto scope = bucket.scope(scope_name);
508
+ auto collection = scope.collection(collection_name);
509
+
510
+ auto key = test::utils::uniq_id("key");
511
+ auto test_value = test::utils::uniq_id("value");
512
+ const tao::json::value document = {
513
+ { "testkey", test_value },
514
+ };
515
+ {
516
+ auto [ctx, resp] = collection.upsert(key, document).get();
517
+ REQUIRE_SUCCESS(ctx.ec());
518
+ }
519
+
520
+ couchbase::analytics_result resp{};
521
+ couchbase::analytics_error_context ctx{};
522
+ CHECK(test::utils::wait_until([&]() {
523
+ std::tie(ctx, resp) =
524
+ scope.analytics_query(fmt::format(R"(SELECT testkey FROM `{}` WHERE testkey = "{}")", collection_name, test_value)).get();
525
+ return !ctx.ec() && resp.meta_data().metrics().result_count() == 1;
526
+ }));
527
+ REQUIRE_SUCCESS(ctx.ec());
528
+ REQUIRE(resp.rows_as_json()[0] == document);
529
+ REQUIRE_FALSE(resp.meta_data().request_id().empty());
530
+ REQUIRE_FALSE(resp.meta_data().client_context_id().empty());
531
+ REQUIRE(resp.meta_data().status() == couchbase::analytics_status::success);
532
+
533
+ {
534
+ const couchbase::core::operations::management::scope_drop_request req{ integration.ctx.bucket, scope_name };
535
+ test::utils::execute(integration.cluster, req);
536
+ }
537
+ }
@@ -228,6 +228,9 @@ TEST_CASE("integration: pessimistic locking", "[integration]")
228
228
  {
229
229
  couchbase::core::operations::get_and_lock_request req{ id };
230
230
  req.lock_time = lock_time;
231
+ if (integration.ctx.deployment == test::utils::deployment_type::capella) {
232
+ req.timeout = std::chrono::seconds{ 2 };
233
+ }
231
234
  auto resp = test::utils::execute(integration.cluster, req);
232
235
  REQUIRE(resp.ctx.ec() == couchbase::errc::common::ambiguous_timeout);
233
236
  REQUIRE(resp.ctx.retried_because_of(couchbase::retry_reason::key_value_locked));
@@ -810,7 +813,11 @@ TEST_CASE("integration: pessimistic locking with public API", "[integration]")
810
813
 
811
814
  // it is not allowed to lock the same key twice
812
815
  {
813
- auto [ctx, resp] = collection.get_and_lock(id, lock_time, {}).get();
816
+ couchbase::get_and_lock_options options{};
817
+ if (integration.ctx.deployment == test::utils::deployment_type::capella) {
818
+ options.timeout(std::chrono::seconds{ 2 });
819
+ }
820
+ auto [ctx, resp] = collection.get_and_lock(id, lock_time, options).get();
814
821
  REQUIRE(ctx.ec() == couchbase::errc::common::ambiguous_timeout);
815
822
  REQUIRE(ctx.retried_because_of(couchbase::retry_reason::key_value_locked));
816
823
  }