couchbase 3.0.0.alpha.3-universal-darwin-19 → 3.0.0.alpha.4-universal-darwin-19

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 (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