couchbase 3.0.0.alpha.3 → 3.0.0.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-6.0.3.yml +4 -1
  3. data/.github/workflows/tests-dev-preview.yml +4 -1
  4. data/.github/workflows/tests.yml +4 -1
  5. data/README.md +1 -1
  6. data/bin/check-cluster +31 -0
  7. data/bin/init-cluster +16 -4
  8. data/examples/analytics.rb +221 -0
  9. data/examples/managing_analytics_indexes.rb +72 -0
  10. data/examples/managing_view_indexes.rb +54 -0
  11. data/examples/search_with_consistency.rb +84 -0
  12. data/examples/view.rb +50 -0
  13. data/ext/.clang-tidy +1 -0
  14. data/ext/build_version.hxx.in +1 -1
  15. data/ext/couchbase/bucket.hxx +0 -1
  16. data/ext/couchbase/couchbase.cxx +1421 -55
  17. data/ext/couchbase/io/dns_client.hxx +215 -0
  18. data/ext/couchbase/io/dns_codec.hxx +207 -0
  19. data/ext/couchbase/io/dns_config.hxx +116 -0
  20. data/ext/couchbase/io/dns_message.hxx +558 -0
  21. data/ext/couchbase/io/http_session.hxx +16 -4
  22. data/ext/couchbase/io/mcbp_session.hxx +2 -1
  23. data/ext/couchbase/mutation_token.hxx +1 -1
  24. data/ext/couchbase/operations.hxx +19 -0
  25. data/ext/couchbase/operations/analytics_dataset_create.hxx +117 -0
  26. data/ext/couchbase/operations/analytics_dataset_drop.hxx +103 -0
  27. data/ext/couchbase/operations/analytics_dataset_get_all.hxx +107 -0
  28. data/ext/couchbase/operations/analytics_dataverse_create.hxx +104 -0
  29. data/ext/couchbase/operations/analytics_dataverse_drop.hxx +104 -0
  30. data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +91 -0
  31. data/ext/couchbase/operations/analytics_index_create.hxx +128 -0
  32. data/ext/couchbase/operations/analytics_index_drop.hxx +110 -0
  33. data/ext/couchbase/operations/analytics_index_get_all.hxx +106 -0
  34. data/ext/couchbase/operations/analytics_link_connect.hxx +102 -0
  35. data/ext/couchbase/operations/analytics_link_disconnect.hxx +101 -0
  36. data/ext/couchbase/operations/design_document.hxx +59 -0
  37. data/ext/couchbase/operations/document_analytics.hxx +293 -0
  38. data/ext/couchbase/operations/document_query.hxx +2 -2
  39. data/ext/couchbase/operations/document_search.hxx +19 -1
  40. data/ext/couchbase/operations/document_view.hxx +227 -0
  41. data/ext/couchbase/operations/search_index.hxx +17 -0
  42. data/ext/couchbase/operations/search_index_control_ingest.hxx +3 -1
  43. data/ext/couchbase/operations/view_index_drop.hxx +67 -0
  44. data/ext/couchbase/operations/view_index_get.hxx +90 -0
  45. data/ext/couchbase/operations/view_index_get_all.hxx +125 -0
  46. data/ext/couchbase/operations/view_index_upsert.hxx +87 -0
  47. data/ext/couchbase/service_type.hxx +38 -1
  48. data/ext/couchbase/timeout_defaults.hxx +3 -1
  49. data/ext/couchbase/utils/connection_string.hxx +231 -0
  50. data/ext/couchbase/version.hxx +1 -1
  51. data/ext/test/main.cxx +3 -12
  52. data/lib/couchbase/analytics_options.rb +165 -0
  53. data/lib/couchbase/bucket.rb +49 -0
  54. data/lib/couchbase/cluster.rb +46 -207
  55. data/lib/couchbase/management/analytics_index_manager.rb +138 -24
  56. data/lib/couchbase/management/view_index_manager.rb +63 -10
  57. data/lib/couchbase/query_options.rb +219 -0
  58. data/lib/couchbase/search_options.rb +6 -6
  59. data/lib/couchbase/version.rb +1 -1
  60. data/lib/couchbase/view_options.rb +155 -0
  61. metadata +34 -2
@@ -243,7 +243,7 @@ struct query_request {
243
243
  tao::json::value scan_vectors = tao::json::empty_object;
244
244
  for (const auto& token : mutation_state) {
245
245
  auto* bucket = scan_vectors.find(token.bucket_name);
246
- if (!bucket) {
246
+ if (bucket == nullptr) {
247
247
  scan_vectors[token.bucket_name] = tao::json::empty_object;
248
248
  bucket = scan_vectors.find(token.bucket_name);
249
249
  }
@@ -254,7 +254,7 @@ struct query_request {
254
254
  body["scan_vectors"] = scan_vectors;
255
255
  }
256
256
  if (check_scan_wait && scan_wait) {
257
- body["scan_wait"] = scan_wait.value();
257
+ body["scan_wait"] = fmt::format("{}ms", scan_wait.value());
258
258
  }
259
259
  for (auto& param : raw) {
260
260
  body[param.first] = param.second;
@@ -131,7 +131,11 @@ struct search_request {
131
131
  {
132
132
  encoded.headers["content-type"] = "application/json";
133
133
  encoded.headers["client-context-id"] = client_context_id;
134
- tao::json::value body{ { "query", query }, { "explain", explain }, { "timeout", fmt::format("{}ms", timeout.count()) } };
134
+ tao::json::value body{
135
+ { "query", query },
136
+ { "explain", explain },
137
+ { "ctl", { { "timeout", timeout.count() } } },
138
+ };
135
139
  if (limit) {
136
140
  body["size"] = *limit;
137
141
  }
@@ -170,6 +174,20 @@ struct search_request {
170
174
  body["facets"][facet.first] = tao::json::from_string(facet.second);
171
175
  }
172
176
  }
177
+ if (!mutation_state.empty()) {
178
+ tao::json::value scan_vectors = tao::json::empty_object;
179
+ for (const auto& token : mutation_state) {
180
+ auto key = fmt::format("{}/{}", token.partition_id, token.partition_uuid);
181
+ auto* old_val = scan_vectors.find(key);
182
+ if (old_val == nullptr || (old_val->is_integer() && old_val->get_unsigned() < token.sequence_number)) {
183
+ scan_vectors[key] = token.sequence_number;
184
+ }
185
+ }
186
+ body["ctl"]["consistency"] = tao::json::value{
187
+ { "level", "at_plus" },
188
+ { "vectors", { { index_name, scan_vectors } } },
189
+ };
190
+ }
173
191
 
174
192
  encoded.method = "POST";
175
193
  encoded.path = fmt::format("/api/index/{}/query", index_name);
@@ -0,0 +1,227 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <tao/json.hpp>
21
+ #include <operations/design_document.hxx>
22
+ #include <utils/url_codec.hxx>
23
+
24
+ namespace couchbase::operations
25
+ {
26
+ struct document_view_response {
27
+ struct meta_data {
28
+ std::optional<std::uint64_t> total_rows{};
29
+ std::optional<std::string> debug_info{};
30
+ };
31
+
32
+ struct row {
33
+ std::optional<std::string> id;
34
+ std::string key;
35
+ std::string value;
36
+ };
37
+
38
+ struct problem {
39
+ std::string code;
40
+ std::string message;
41
+ };
42
+
43
+ std::string client_context_id;
44
+ std::error_code ec;
45
+ document_view_response::meta_data meta_data{};
46
+ std::vector<document_view_response::row> rows{};
47
+ std::optional<problem> error{};
48
+ };
49
+
50
+ struct document_view_request {
51
+ using response_type = document_view_response;
52
+ using encoded_request_type = io::http_request;
53
+ using encoded_response_type = io::http_response;
54
+
55
+ static const inline service_type type = service_type::views;
56
+
57
+ std::string client_context_id{ uuid::to_string(uuid::random()) };
58
+ std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
59
+
60
+ std::string bucket_name;
61
+ std::string document_name;
62
+ std::string view_name;
63
+ design_document::name_space name_space;
64
+
65
+ std::optional<std::uint64_t> limit;
66
+ std::optional<std::uint64_t> skip;
67
+
68
+ enum class scan_consistency {
69
+ not_bounded,
70
+ update_after,
71
+ request_plus,
72
+ };
73
+ std::optional<scan_consistency> consistency;
74
+
75
+ std::vector<std::string> keys;
76
+
77
+ std::optional<std::string> key;
78
+ std::optional<std::string> start_key;
79
+ std::optional<std::string> end_key;
80
+ std::optional<std::string> start_key_doc_id;
81
+ std::optional<std::string> end_key_doc_id;
82
+ std::optional<bool> inclusive_end;
83
+
84
+ std::optional<bool> reduce;
85
+ std::optional<bool> group;
86
+ std::optional<std::uint32_t> group_level;
87
+ bool debug{ false };
88
+
89
+ enum class sort_order { ascending, descending };
90
+ std::optional<sort_order> order;
91
+
92
+ void encode_to(encoded_request_type& encoded)
93
+ {
94
+ std::vector<std::string> query_string;
95
+
96
+ if (debug) {
97
+ query_string.emplace_back("debug=true");
98
+ }
99
+ if (limit) {
100
+ query_string.emplace_back(fmt::format("limit={}", *limit));
101
+ }
102
+ if (skip) {
103
+ query_string.emplace_back(fmt::format("skip={}", *skip));
104
+ }
105
+ if (consistency) {
106
+ switch (*consistency) {
107
+ case scan_consistency::not_bounded:
108
+ query_string.emplace_back("stale=ok");
109
+ break;
110
+ case scan_consistency::update_after:
111
+ query_string.emplace_back("stale=update_after");
112
+ break;
113
+ case scan_consistency::request_plus:
114
+ query_string.emplace_back("stale=false");
115
+ break;
116
+ }
117
+ }
118
+ if (key) {
119
+ query_string.emplace_back(fmt::format("key={}", utils::string_codec::form_encode(*key)));
120
+ }
121
+ if (start_key) {
122
+ query_string.emplace_back(fmt::format("start_key={}", utils::string_codec::form_encode(*start_key)));
123
+ }
124
+ if (end_key) {
125
+ query_string.emplace_back(fmt::format("end_key={}", utils::string_codec::form_encode(*end_key)));
126
+ }
127
+ if (start_key_doc_id) {
128
+ query_string.emplace_back(fmt::format("start_key_doc_id={}", utils::string_codec::form_encode(*start_key_doc_id)));
129
+ }
130
+ if (end_key_doc_id) {
131
+ query_string.emplace_back(fmt::format("end_key_doc_id={}", utils::string_codec::form_encode(*end_key_doc_id)));
132
+ }
133
+ if (inclusive_end) {
134
+ query_string.emplace_back(fmt::format("inclusive_end={}", inclusive_end.value() ? "true" : "false"));
135
+ }
136
+ if (reduce) {
137
+ query_string.emplace_back(fmt::format("reduce={}", reduce.value() ? "true" : "false"));
138
+ }
139
+ if (group) {
140
+ query_string.emplace_back(fmt::format("group={}", group.value() ? "true" : "false"));
141
+ }
142
+ if (group_level) {
143
+ query_string.emplace_back(fmt::format("group_level={}", *group_level));
144
+ }
145
+ if (order) {
146
+ switch (*order) {
147
+ case sort_order::descending:
148
+ query_string.emplace_back("descending=true");
149
+ break;
150
+ case sort_order::ascending:
151
+ query_string.emplace_back("descending=false");
152
+ break;
153
+ }
154
+ }
155
+
156
+ tao::json::value body = tao::json::empty_object;
157
+ if (!keys.empty()) {
158
+ tao::json::value keys_array = tao::json::empty_array;
159
+ for (const auto& entry : keys) {
160
+ keys_array.push_back(tao::json::from_string(entry));
161
+ }
162
+ body["keys"] = keys_array;
163
+ }
164
+
165
+ encoded.method = "POST";
166
+ encoded.headers["content-type"] = "application/json";
167
+ encoded.path = fmt::format("/{}/_design/{}{}/_view/{}?{}",
168
+ bucket_name,
169
+ name_space == design_document::name_space::development ? "dev_" : "",
170
+ document_name,
171
+ view_name,
172
+ fmt::join(query_string, "&"));
173
+ encoded.body = tao::json::to_string(body);
174
+ }
175
+ };
176
+
177
+ document_view_response
178
+ make_response(std::error_code ec, document_view_request& request, document_view_request::encoded_response_type encoded)
179
+ {
180
+ document_view_response response{ request.client_context_id, ec };
181
+ if (!ec) {
182
+ if (encoded.status_code == 200) {
183
+ tao::json::value payload = tao::json::from_string(encoded.body);
184
+ const auto* total_rows = payload.find("total_rows");
185
+ if (total_rows != nullptr && total_rows->is_unsigned()) {
186
+ response.meta_data.total_rows = total_rows->get_unsigned();
187
+ }
188
+ const auto* debug_info = payload.find("debug_info");
189
+ if (debug_info != nullptr && debug_info->is_object()) {
190
+ response.meta_data.debug_info.emplace(tao::json::to_string(*debug_info));
191
+ }
192
+ const auto* rows = payload.find("rows");
193
+ if (rows != nullptr && rows->is_array()) {
194
+ for (const auto& entry : rows->get_array()) {
195
+ document_view_response::row row{};
196
+ const auto *id = entry.find("id");
197
+ if (id != nullptr && id->is_string()) {
198
+ row.id = id->get_string();
199
+ }
200
+ row.key = tao::json::to_string(entry.at("key"));
201
+ row.value = tao::json::to_string(entry.at("value"));
202
+ response.rows.emplace_back(row);
203
+ }
204
+ }
205
+ } else if (encoded.status_code == 400) {
206
+ tao::json::value payload = tao::json::from_string(encoded.body);
207
+ document_view_response::problem problem{};
208
+ const auto* error = payload.find("error");
209
+ if (error != nullptr && error->is_string()) {
210
+ problem.code = error->get_string();
211
+ }
212
+ const auto* reason = payload.find("reason");
213
+ if (reason != nullptr && reason->is_string()) {
214
+ problem.message = reason->get_string();
215
+ }
216
+ response.error.emplace(problem);
217
+ response.ec = std::make_error_code(error::common_errc::invalid_argument);
218
+ } else if (encoded.status_code == 404) {
219
+ response.ec = std::make_error_code(error::view_errc::design_document_not_found);
220
+ } else {
221
+ response.ec = std::make_error_code(error::common_errc::internal_server_failure);
222
+ }
223
+ }
224
+ return response;
225
+ }
226
+
227
+ } // namespace couchbase::operations
@@ -1,3 +1,20 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
1
18
  #pragma once
2
19
 
3
20
  namespace couchbase::operations
@@ -51,7 +51,9 @@ struct search_index_control_ingest_request {
51
51
  };
52
52
 
53
53
  search_index_control_ingest_response
54
- make_response(std::error_code ec, search_index_control_ingest_request& request, search_index_control_ingest_request::encoded_response_type encoded)
54
+ make_response(std::error_code ec,
55
+ search_index_control_ingest_request& request,
56
+ search_index_control_ingest_request::encoded_response_type encoded)
55
57
  {
56
58
  search_index_control_ingest_response response{ request.client_context_id, ec };
57
59
  if (!ec) {
@@ -0,0 +1,67 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <tao/json.hpp>
21
+
22
+ namespace couchbase::operations
23
+ {
24
+ struct view_index_drop_response {
25
+ std::string client_context_id;
26
+ std::error_code ec;
27
+ };
28
+
29
+ struct view_index_drop_request {
30
+ using response_type = view_index_drop_response;
31
+ using encoded_request_type = io::http_request;
32
+ using encoded_response_type = io::http_response;
33
+
34
+ static const inline service_type type = service_type::views;
35
+
36
+ std::string client_context_id{ uuid::to_string(uuid::random()) };
37
+ std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
38
+
39
+ std::string bucket_name;
40
+ std::string document_name;
41
+ design_document::name_space name_space;
42
+
43
+ void encode_to(encoded_request_type& encoded)
44
+ {
45
+ encoded.method = "DELETE";
46
+ encoded.path =
47
+ fmt::format("/{}/_design/{}{}", bucket_name, name_space == design_document::name_space::development ? "dev_" : "", document_name);
48
+ }
49
+ };
50
+
51
+ view_index_drop_response
52
+ make_response(std::error_code ec, view_index_drop_request& request, view_index_drop_request::encoded_response_type encoded)
53
+ {
54
+ view_index_drop_response response{ request.client_context_id, ec };
55
+ if (!ec) {
56
+ if (encoded.status_code == 200) {
57
+
58
+ } else if (encoded.status_code == 404) {
59
+ response.ec = std::make_error_code(error::view_errc::design_document_not_found);
60
+ } else {
61
+ response.ec = std::make_error_code(error::common_errc::internal_server_failure);
62
+ }
63
+ }
64
+ return response;
65
+ }
66
+
67
+ } // namespace couchbase::operations
@@ -0,0 +1,90 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2020 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #pragma once
19
+
20
+ #include <tao/json.hpp>
21
+ #include <operations/design_document.hxx>
22
+
23
+ namespace couchbase::operations
24
+ {
25
+ struct view_index_get_response {
26
+ std::string client_context_id;
27
+ std::error_code ec;
28
+ design_document document{};
29
+ };
30
+
31
+ struct view_index_get_request {
32
+ using response_type = view_index_get_response;
33
+ using encoded_request_type = io::http_request;
34
+ using encoded_response_type = io::http_response;
35
+
36
+ static const inline service_type type = service_type::views;
37
+
38
+ std::string client_context_id{ uuid::to_string(uuid::random()) };
39
+ std::chrono::milliseconds timeout{ timeout_defaults::management_timeout };
40
+
41
+ std::string bucket_name;
42
+ std::string document_name;
43
+ design_document::name_space name_space;
44
+
45
+ void encode_to(encoded_request_type& encoded)
46
+ {
47
+ encoded.method = "GET";
48
+ encoded.path =
49
+ fmt::format("/{}/_design/{}{}", bucket_name, name_space == design_document::name_space::development ? "dev_" : "", document_name);
50
+ }
51
+ };
52
+
53
+ view_index_get_response
54
+ make_response(std::error_code ec, view_index_get_request& request, view_index_get_request::encoded_response_type encoded)
55
+ {
56
+ view_index_get_response response{ request.client_context_id, ec };
57
+ if (!ec) {
58
+ if (encoded.status_code == 200) {
59
+ response.document.name = request.document_name;
60
+ response.document.ns = request.name_space;
61
+
62
+ auto payload = tao::json::from_string(encoded.body);
63
+ const auto* views = payload.find("views");
64
+ if (views != nullptr && views->is_object()) {
65
+ for (const auto& view_entry : views->get_object()) {
66
+ couchbase::operations::design_document::view view;
67
+ view.name = view_entry.first;
68
+ if (view_entry.second.is_object()) {
69
+ const auto* map = view_entry.second.find("map");
70
+ if (map != nullptr && map->is_string()) {
71
+ view.map = map->get_string();
72
+ }
73
+ const auto* reduce = view_entry.second.find("reduce");
74
+ if (reduce != nullptr && reduce->is_string()) {
75
+ view.reduce = reduce->get_string();
76
+ }
77
+ }
78
+ response.document.views[view.name] = view;
79
+ }
80
+ }
81
+ } else if (encoded.status_code == 404) {
82
+ response.ec = std::make_error_code(error::view_errc::design_document_not_found);
83
+ } else {
84
+ response.ec = std::make_error_code(error::common_errc::internal_server_failure);
85
+ }
86
+ }
87
+ return response;
88
+ }
89
+
90
+ } // namespace couchbase::operations