couchbase 3.0.0.alpha.3-universal-darwin-19 → 3.0.0.alpha.4-universal-darwin-19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/tests-6.0.3.yml +4 -1
- data/.github/workflows/tests-dev-preview.yml +4 -1
- data/.github/workflows/tests.yml +4 -1
- data/README.md +1 -1
- data/bin/check-cluster +31 -0
- data/bin/init-cluster +16 -4
- data/examples/analytics.rb +221 -0
- data/examples/managing_analytics_indexes.rb +72 -0
- data/examples/managing_view_indexes.rb +54 -0
- data/examples/search_with_consistency.rb +84 -0
- data/examples/view.rb +50 -0
- data/ext/.clang-tidy +1 -0
- data/ext/build_version.hxx.in +1 -1
- data/ext/couchbase/bucket.hxx +0 -1
- data/ext/couchbase/couchbase.cxx +1421 -55
- data/ext/couchbase/io/dns_client.hxx +215 -0
- data/ext/couchbase/io/dns_codec.hxx +207 -0
- data/ext/couchbase/io/dns_config.hxx +116 -0
- data/ext/couchbase/io/dns_message.hxx +558 -0
- data/ext/couchbase/io/http_session.hxx +16 -4
- data/ext/couchbase/io/mcbp_session.hxx +2 -1
- data/ext/couchbase/mutation_token.hxx +1 -1
- data/ext/couchbase/operations.hxx +19 -0
- data/ext/couchbase/operations/analytics_dataset_create.hxx +117 -0
- data/ext/couchbase/operations/analytics_dataset_drop.hxx +103 -0
- data/ext/couchbase/operations/analytics_dataset_get_all.hxx +107 -0
- data/ext/couchbase/operations/analytics_dataverse_create.hxx +104 -0
- data/ext/couchbase/operations/analytics_dataverse_drop.hxx +104 -0
- data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +91 -0
- data/ext/couchbase/operations/analytics_index_create.hxx +128 -0
- data/ext/couchbase/operations/analytics_index_drop.hxx +110 -0
- data/ext/couchbase/operations/analytics_index_get_all.hxx +106 -0
- data/ext/couchbase/operations/analytics_link_connect.hxx +102 -0
- data/ext/couchbase/operations/analytics_link_disconnect.hxx +101 -0
- data/ext/couchbase/operations/design_document.hxx +59 -0
- data/ext/couchbase/operations/document_analytics.hxx +293 -0
- data/ext/couchbase/operations/document_query.hxx +2 -2
- data/ext/couchbase/operations/document_search.hxx +19 -1
- data/ext/couchbase/operations/document_view.hxx +227 -0
- data/ext/couchbase/operations/search_index.hxx +17 -0
- data/ext/couchbase/operations/search_index_control_ingest.hxx +3 -1
- data/ext/couchbase/operations/view_index_drop.hxx +67 -0
- data/ext/couchbase/operations/view_index_get.hxx +90 -0
- data/ext/couchbase/operations/view_index_get_all.hxx +125 -0
- data/ext/couchbase/operations/view_index_upsert.hxx +87 -0
- data/ext/couchbase/service_type.hxx +38 -1
- data/ext/couchbase/timeout_defaults.hxx +3 -1
- data/ext/couchbase/utils/connection_string.hxx +231 -0
- data/ext/couchbase/version.hxx +1 -1
- data/ext/test/main.cxx +3 -12
- data/lib/couchbase/analytics_options.rb +165 -0
- data/lib/couchbase/bucket.rb +49 -0
- data/lib/couchbase/cluster.rb +46 -207
- data/lib/couchbase/management/analytics_index_manager.rb +138 -24
- data/lib/couchbase/management/view_index_manager.rb +63 -10
- data/lib/couchbase/query_options.rb +219 -0
- data/lib/couchbase/search_options.rb +6 -6
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view_options.rb +155 -0
- metadata +34 -2
@@ -0,0 +1,125 @@
|
|
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_all_response {
|
26
|
+
std::string client_context_id;
|
27
|
+
std::error_code ec;
|
28
|
+
std::vector<design_document> design_documents{};
|
29
|
+
};
|
30
|
+
|
31
|
+
struct view_index_get_all_request {
|
32
|
+
using response_type = view_index_get_all_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::management;
|
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
|
+
design_document::name_space name_space;
|
43
|
+
|
44
|
+
void encode_to(encoded_request_type& encoded)
|
45
|
+
{
|
46
|
+
encoded.method = "GET";
|
47
|
+
encoded.path = fmt::format("/pools/default/buckets/{}/ddocs", bucket_name);
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
view_index_get_all_response
|
52
|
+
make_response(std::error_code ec, view_index_get_all_request& request, view_index_get_all_request::encoded_response_type encoded)
|
53
|
+
{
|
54
|
+
view_index_get_all_response response{ request.client_context_id, ec };
|
55
|
+
if (!ec) {
|
56
|
+
if (encoded.status_code == 200) {
|
57
|
+
auto payload = tao::json::from_string(encoded.body);
|
58
|
+
auto* rows = payload.find("rows");
|
59
|
+
if (rows != nullptr && rows->is_array()) {
|
60
|
+
for (const auto& entry : rows->get_array()) {
|
61
|
+
const auto* dd = entry.find("doc");
|
62
|
+
if (dd == nullptr || !dd->is_object()) {
|
63
|
+
continue;
|
64
|
+
}
|
65
|
+
const auto* meta = dd->find("meta");
|
66
|
+
if (meta == nullptr || !meta->is_object()) {
|
67
|
+
continue;
|
68
|
+
}
|
69
|
+
|
70
|
+
design_document document{};
|
71
|
+
document.rev = meta->at("rev").get_string();
|
72
|
+
auto id = meta->at("id").get_string();
|
73
|
+
static const std::string prefix = "_design/";
|
74
|
+
if (id.find(prefix) == 0) {
|
75
|
+
document.name = id.substr(prefix.size());
|
76
|
+
} else {
|
77
|
+
document.name = id; // fall back, should not happen
|
78
|
+
}
|
79
|
+
static const std::string name_space_prefix = "dev_";
|
80
|
+
if (document.name.find(name_space_prefix) == 0) {
|
81
|
+
document.name = document.name.substr(name_space_prefix.size());
|
82
|
+
document.ns = couchbase::operations::design_document::name_space::development;
|
83
|
+
} else {
|
84
|
+
document.ns = couchbase::operations::design_document::name_space::production;
|
85
|
+
}
|
86
|
+
if (document.ns != request.name_space) {
|
87
|
+
continue;
|
88
|
+
}
|
89
|
+
|
90
|
+
const auto *json = dd->find("json");
|
91
|
+
if (json == nullptr || !json->is_object()) {
|
92
|
+
continue;
|
93
|
+
}
|
94
|
+
const auto* views = json->find("views");
|
95
|
+
if (views != nullptr && views->is_object()) {
|
96
|
+
for (const auto& view_entry : views->get_object()) {
|
97
|
+
couchbase::operations::design_document::view view;
|
98
|
+
view.name = view_entry.first;
|
99
|
+
if (view_entry.second.is_object()) {
|
100
|
+
const auto* map = view_entry.second.find("map");
|
101
|
+
if (map != nullptr && map->is_string()) {
|
102
|
+
view.map = map->get_string();
|
103
|
+
}
|
104
|
+
const auto* reduce = view_entry.second.find("reduce");
|
105
|
+
if (reduce != nullptr && reduce->is_string()) {
|
106
|
+
view.reduce = reduce->get_string();
|
107
|
+
}
|
108
|
+
}
|
109
|
+
document.views[view.name] = view;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
response.design_documents.emplace_back(document);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
} else if (encoded.status_code == 404) {
|
117
|
+
response.ec = std::make_error_code(error::common_errc::bucket_not_found);
|
118
|
+
} else {
|
119
|
+
response.ec = std::make_error_code(error::common_errc::internal_server_failure);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
return response;
|
123
|
+
}
|
124
|
+
|
125
|
+
} // namespace couchbase::operations
|
@@ -0,0 +1,87 @@
|
|
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_upsert_response {
|
25
|
+
std::string client_context_id;
|
26
|
+
std::error_code ec;
|
27
|
+
};
|
28
|
+
|
29
|
+
struct view_index_upsert_request {
|
30
|
+
using response_type = view_index_upsert_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
|
+
design_document document;
|
41
|
+
|
42
|
+
void encode_to(encoded_request_type& encoded)
|
43
|
+
{
|
44
|
+
tao::json::value body;
|
45
|
+
body["views"] = tao::json::empty_object;
|
46
|
+
for (const auto& view : document.views) {
|
47
|
+
tao::json::value view_def;
|
48
|
+
if (view.second.map) {
|
49
|
+
view_def["map"] = *view.second.map;
|
50
|
+
}
|
51
|
+
if (view.second.reduce) {
|
52
|
+
view_def["reduce"] = *view.second.reduce;
|
53
|
+
}
|
54
|
+
body["views"][view.first] = view_def;
|
55
|
+
}
|
56
|
+
|
57
|
+
encoded.headers["content-type"] = "application/json";
|
58
|
+
encoded.method = "PUT";
|
59
|
+
encoded.path = fmt::format(
|
60
|
+
"/{}/_design/{}{}", bucket_name, document.ns == design_document::name_space::development ? "dev_" : "", document.name);
|
61
|
+
encoded.body = tao::json::to_string(body);
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
view_index_upsert_response
|
66
|
+
make_response(std::error_code ec, view_index_upsert_request& request, view_index_upsert_request::encoded_response_type encoded)
|
67
|
+
{
|
68
|
+
view_index_upsert_response response{ request.client_context_id, ec };
|
69
|
+
if (!ec) {
|
70
|
+
switch (encoded.status_code) {
|
71
|
+
case 200:
|
72
|
+
case 201:
|
73
|
+
break;
|
74
|
+
case 400:
|
75
|
+
response.ec = std::make_error_code(error::common_errc::invalid_argument);
|
76
|
+
break;
|
77
|
+
case 404:
|
78
|
+
response.ec = std::make_error_code(error::view_errc::design_document_not_found);
|
79
|
+
break;
|
80
|
+
default:
|
81
|
+
response.ec = std::make_error_code(error::common_errc::internal_server_failure);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
return response;
|
85
|
+
}
|
86
|
+
|
87
|
+
} // namespace couchbase::operations
|
@@ -19,5 +19,42 @@
|
|
19
19
|
|
20
20
|
namespace couchbase
|
21
21
|
{
|
22
|
-
enum class service_type {
|
22
|
+
enum class service_type {
|
23
|
+
kv,
|
24
|
+
query,
|
25
|
+
analytics,
|
26
|
+
search,
|
27
|
+
views,
|
28
|
+
management,
|
29
|
+
};
|
23
30
|
}
|
31
|
+
|
32
|
+
template<>
|
33
|
+
struct fmt::formatter<couchbase::service_type> : formatter<std::string_view> {
|
34
|
+
template<typename FormatContext>
|
35
|
+
auto format(couchbase::service_type type, FormatContext& ctx)
|
36
|
+
{
|
37
|
+
string_view name = "unknown";
|
38
|
+
switch (type) {
|
39
|
+
case couchbase::service_type::kv:
|
40
|
+
name = "kv";
|
41
|
+
break;
|
42
|
+
case couchbase::service_type::query:
|
43
|
+
name = "query";
|
44
|
+
break;
|
45
|
+
case couchbase::service_type::analytics:
|
46
|
+
name = "analytics";
|
47
|
+
break;
|
48
|
+
case couchbase::service_type::search:
|
49
|
+
name = "search";
|
50
|
+
break;
|
51
|
+
case couchbase::service_type::views:
|
52
|
+
name = "views";
|
53
|
+
break;
|
54
|
+
case couchbase::service_type::management:
|
55
|
+
name = "management";
|
56
|
+
break;
|
57
|
+
}
|
58
|
+
return formatter<string_view>::format(name, ctx);
|
59
|
+
}
|
60
|
+
};
|
@@ -29,4 +29,6 @@ constexpr std::chrono::milliseconds query_timeout{ 75'000 };
|
|
29
29
|
constexpr std::chrono::milliseconds analytics_timeout{ 75'000 };
|
30
30
|
constexpr std::chrono::milliseconds search_timeout{ 75'000 };
|
31
31
|
constexpr std::chrono::milliseconds management_timeout{ 75'000 };
|
32
|
-
|
32
|
+
|
33
|
+
constexpr std::chrono::milliseconds dns_srv_timeout{ 500 };
|
34
|
+
} // namespace couchbase::timeout_defaults
|
@@ -0,0 +1,231 @@
|
|
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 <string>
|
21
|
+
|
22
|
+
#include <tao/json/external/pegtl.hpp>
|
23
|
+
#include <tao/json/external/pegtl/contrib/uri.hpp>
|
24
|
+
|
25
|
+
namespace couchbase::utils
|
26
|
+
{
|
27
|
+
|
28
|
+
struct connection_string {
|
29
|
+
enum class bootstrap_mode {
|
30
|
+
unspecified,
|
31
|
+
gcccp,
|
32
|
+
http,
|
33
|
+
};
|
34
|
+
|
35
|
+
enum class address_type {
|
36
|
+
ipv4,
|
37
|
+
ipv6,
|
38
|
+
dns,
|
39
|
+
};
|
40
|
+
|
41
|
+
struct node {
|
42
|
+
std::string address;
|
43
|
+
std::uint16_t port;
|
44
|
+
address_type type;
|
45
|
+
bootstrap_mode mode{ bootstrap_mode::unspecified };
|
46
|
+
};
|
47
|
+
|
48
|
+
std::string scheme{};
|
49
|
+
bool tls{ false };
|
50
|
+
std::map<std::string, std::string> params{};
|
51
|
+
std::vector<node> bootstrap_nodes{};
|
52
|
+
|
53
|
+
std::optional<std::string> default_bucket_name{};
|
54
|
+
bootstrap_mode default_mode{ bootstrap_mode::unspecified };
|
55
|
+
std::uint16_t default_port{ 0 };
|
56
|
+
|
57
|
+
std::optional<std::string> error{};
|
58
|
+
};
|
59
|
+
|
60
|
+
namespace priv
|
61
|
+
{
|
62
|
+
using namespace tao::json::pegtl;
|
63
|
+
|
64
|
+
struct bucket_name : seq<uri::segment_nz> {
|
65
|
+
};
|
66
|
+
using param_key = star<sor<abnf::ALPHA, abnf::DIGIT, one<'_'>>>;
|
67
|
+
using param_value = star<sor<minus<uri::pchar, one<'=', '&', '?'>>, one<'/'>>>;
|
68
|
+
struct param : seq<param_key, one<'='>, param_value> {
|
69
|
+
};
|
70
|
+
|
71
|
+
using sub_delims = minus<uri::sub_delims, one<',', '='>>; // host and mode separators
|
72
|
+
struct reg_name : star<sor<uri::unreserved, uri::pct_encoded, sub_delims>> {
|
73
|
+
};
|
74
|
+
struct host : sor<uri::IP_literal, uri::IPv4address, reg_name> {
|
75
|
+
};
|
76
|
+
|
77
|
+
struct mode : sor<istring<'c', 'c', 'c', 'p'>, istring<'g', 'c', 'c', 'c', 'p'>, istring<'h', 't', 't', 'p'>, istring<'m', 'c', 'd'>> {
|
78
|
+
};
|
79
|
+
using node = seq<host, opt<uri::colon, uri::port>, opt<one<'='>, mode>>;
|
80
|
+
|
81
|
+
using opt_bucket_name = opt_must<one<'/'>, bucket_name>;
|
82
|
+
using opt_params = opt_must<one<'?'>, list_must<param, one<'&'>>>;
|
83
|
+
using opt_nodes = seq<list_must<node, one<',', ';'>>, opt_bucket_name>;
|
84
|
+
|
85
|
+
using grammar = must<seq<uri::scheme, one<':'>, uri::dslash, opt_nodes, opt_params, eof>>;
|
86
|
+
|
87
|
+
template<typename Rule>
|
88
|
+
struct action {
|
89
|
+
};
|
90
|
+
|
91
|
+
template<>
|
92
|
+
struct action<uri::scheme> {
|
93
|
+
template<typename ActionInput>
|
94
|
+
static void apply(const ActionInput& in, connection_string& cs, connection_string::node& /* cur_node */)
|
95
|
+
{
|
96
|
+
cs.scheme = in.string();
|
97
|
+
if (cs.scheme == "couchbase") {
|
98
|
+
cs.default_port = 11210;
|
99
|
+
cs.default_mode = connection_string::bootstrap_mode::gcccp;
|
100
|
+
cs.tls = false;
|
101
|
+
} else if (cs.scheme == "couchbases") {
|
102
|
+
cs.default_port = 11207;
|
103
|
+
cs.default_mode = connection_string::bootstrap_mode::gcccp;
|
104
|
+
cs.tls = true;
|
105
|
+
} else if (cs.scheme == "http") {
|
106
|
+
cs.default_port = 8091;
|
107
|
+
cs.default_mode = connection_string::bootstrap_mode::http;
|
108
|
+
cs.tls = false;
|
109
|
+
} else if (cs.scheme == "https") {
|
110
|
+
cs.default_port = 18091;
|
111
|
+
cs.default_mode = connection_string::bootstrap_mode::http;
|
112
|
+
cs.tls = true;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
};
|
116
|
+
|
117
|
+
template<>
|
118
|
+
struct action<param> {
|
119
|
+
template<typename ActionInput>
|
120
|
+
static void apply(const ActionInput& in, connection_string& cs, connection_string::node& /* cur_node */)
|
121
|
+
{
|
122
|
+
const auto& pair = in.string();
|
123
|
+
auto eq = pair.find('=');
|
124
|
+
std::string key = pair.substr(0, eq);
|
125
|
+
cs.params[key] = (eq == std::string::npos) ? "" : pair.substr(eq + 1);
|
126
|
+
}
|
127
|
+
};
|
128
|
+
|
129
|
+
template<>
|
130
|
+
struct action<reg_name> {
|
131
|
+
template<typename ActionInput>
|
132
|
+
static void apply(const ActionInput& in, connection_string& /* cs */, connection_string::node& cur_node)
|
133
|
+
{
|
134
|
+
cur_node.type = connection_string::address_type::dns;
|
135
|
+
cur_node.address = in.string_view();
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
template<>
|
140
|
+
struct action<uri::IPv4address> {
|
141
|
+
template<typename ActionInput>
|
142
|
+
static void apply(const ActionInput& in, connection_string& /* cs */, connection_string::node& cur_node)
|
143
|
+
{
|
144
|
+
cur_node.type = connection_string::address_type::ipv4;
|
145
|
+
cur_node.address = in.string_view();
|
146
|
+
}
|
147
|
+
};
|
148
|
+
|
149
|
+
template<>
|
150
|
+
struct action<uri::IPv6address> {
|
151
|
+
template<typename ActionInput>
|
152
|
+
static void apply(const ActionInput& in, connection_string& /* cs */, connection_string::node& cur_node)
|
153
|
+
{
|
154
|
+
cur_node.type = connection_string::address_type::ipv6;
|
155
|
+
cur_node.address = in.string_view();
|
156
|
+
}
|
157
|
+
};
|
158
|
+
|
159
|
+
template<>
|
160
|
+
struct action<node> {
|
161
|
+
template<typename ActionInput>
|
162
|
+
static void apply(const ActionInput& /* in */, connection_string& cs, connection_string::node& cur_node)
|
163
|
+
{
|
164
|
+
cs.bootstrap_nodes.push_back(cur_node);
|
165
|
+
cur_node = {};
|
166
|
+
}
|
167
|
+
};
|
168
|
+
|
169
|
+
template<>
|
170
|
+
struct action<uri::port> {
|
171
|
+
template<typename ActionInput>
|
172
|
+
static void apply(const ActionInput& in, connection_string& /* cs */, connection_string::node& cur_node)
|
173
|
+
{
|
174
|
+
cur_node.port = static_cast<std::uint16_t>(std::stoul(in.string()));
|
175
|
+
}
|
176
|
+
};
|
177
|
+
|
178
|
+
template<>
|
179
|
+
struct action<mode> {
|
180
|
+
template<typename ActionInput>
|
181
|
+
static void apply(const ActionInput& in, connection_string& /* cs */, connection_string::node& cur_node)
|
182
|
+
{
|
183
|
+
std::string mode = in.string();
|
184
|
+
std::transform(mode.begin(), mode.end(), mode.begin(), [](unsigned char c) { return std::tolower(c); });
|
185
|
+
if (mode == "mcd" || mode == "gcccp" || mode == "cccp") {
|
186
|
+
cur_node.mode = connection_string::bootstrap_mode::gcccp;
|
187
|
+
} else if (mode == "http") {
|
188
|
+
cur_node.mode = connection_string::bootstrap_mode::http;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
};
|
192
|
+
|
193
|
+
template<>
|
194
|
+
struct action<bucket_name> {
|
195
|
+
template<typename ActionInput>
|
196
|
+
static void apply(const ActionInput& in, connection_string& cs, connection_string::node& /* cur_node */)
|
197
|
+
{
|
198
|
+
cs.default_bucket_name = in.string();
|
199
|
+
}
|
200
|
+
};
|
201
|
+
} // namespace priv
|
202
|
+
|
203
|
+
static connection_string
|
204
|
+
parse_connection_string(const std::string& input)
|
205
|
+
{
|
206
|
+
connection_string res;
|
207
|
+
|
208
|
+
if (input.empty()) {
|
209
|
+
res.error = "failed to parse connection string: empty input";
|
210
|
+
return res;
|
211
|
+
}
|
212
|
+
|
213
|
+
auto in = tao::json::pegtl::memory_input(input, __FUNCTION__);
|
214
|
+
try {
|
215
|
+
connection_string::node node{};
|
216
|
+
tao::json::pegtl::parse<priv::grammar, priv::action>(in, res, node);
|
217
|
+
} catch (tao::json::pegtl::parse_error& e) {
|
218
|
+
for (const auto& position : e.positions) {
|
219
|
+
if (position.source == __FUNCTION__) {
|
220
|
+
res.error = fmt::format(
|
221
|
+
"failed to parse connection string (column: {}, trailer: \"{}\")", position.byte_in_line, input.substr(position.byte));
|
222
|
+
break;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
if (!res.error) {
|
226
|
+
res.error = e.what();
|
227
|
+
}
|
228
|
+
}
|
229
|
+
return res;
|
230
|
+
}
|
231
|
+
} // namespace couchbase::utils
|