couchbase 3.5.0-arm64-darwin-22
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +202 -0
- data/README.md +154 -0
- data/ext/extconf.rb +0 -0
- data/lib/active_support/cache/couchbase_store.rb +339 -0
- data/lib/couchbase/3.0/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.1/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.2/libcouchbase.bundle +0 -0
- data/lib/couchbase/3.3/libcouchbase.bundle +0 -0
- data/lib/couchbase/analytics_options.rb +107 -0
- data/lib/couchbase/authenticator.rb +64 -0
- data/lib/couchbase/binary_collection.rb +128 -0
- data/lib/couchbase/binary_collection_options.rb +24 -0
- data/lib/couchbase/bucket.rb +144 -0
- data/lib/couchbase/cluster.rb +460 -0
- data/lib/couchbase/cluster_registry.rb +49 -0
- data/lib/couchbase/collection.rb +705 -0
- data/lib/couchbase/collection_options.rb +399 -0
- data/lib/couchbase/config_profiles.rb +55 -0
- data/lib/couchbase/configuration.rb +56 -0
- data/lib/couchbase/datastructures/couchbase_list.rb +160 -0
- data/lib/couchbase/datastructures/couchbase_map.rb +194 -0
- data/lib/couchbase/datastructures/couchbase_queue.rb +134 -0
- data/lib/couchbase/datastructures/couchbase_set.rb +128 -0
- data/lib/couchbase/datastructures.rb +24 -0
- data/lib/couchbase/diagnostics.rb +181 -0
- data/lib/couchbase/errors.rb +376 -0
- data/lib/couchbase/json_transcoder.rb +39 -0
- data/lib/couchbase/key_value_scan.rb +117 -0
- data/lib/couchbase/libcouchbase.rb +6 -0
- data/lib/couchbase/logger.rb +85 -0
- data/lib/couchbase/management/analytics_index_manager.rb +1127 -0
- data/lib/couchbase/management/bucket_manager.rb +443 -0
- data/lib/couchbase/management/collection_manager.rb +470 -0
- data/lib/couchbase/management/collection_query_index_manager.rb +222 -0
- data/lib/couchbase/management/query_index_manager.rb +617 -0
- data/lib/couchbase/management/scope_search_index_manager.rb +198 -0
- data/lib/couchbase/management/search_index_manager.rb +424 -0
- data/lib/couchbase/management/user_manager.rb +468 -0
- data/lib/couchbase/management/view_index_manager.rb +237 -0
- data/lib/couchbase/management.rb +29 -0
- data/lib/couchbase/mutation_state.rb +63 -0
- data/lib/couchbase/options.rb +2837 -0
- data/lib/couchbase/protostellar/binary_collection.rb +55 -0
- data/lib/couchbase/protostellar/bucket.rb +51 -0
- data/lib/couchbase/protostellar/client.rb +99 -0
- data/lib/couchbase/protostellar/cluster.rb +163 -0
- data/lib/couchbase/protostellar/collection.rb +152 -0
- data/lib/couchbase/protostellar/connect_options.rb +63 -0
- data/lib/couchbase/protostellar/error_handling.rb +203 -0
- data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +61 -0
- data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +35 -0
- data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +61 -0
- data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +37 -0
- data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +72 -0
- data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +44 -0
- data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +52 -0
- data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +70 -0
- data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +97 -0
- data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +46 -0
- data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +52 -0
- data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +99 -0
- data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +57 -0
- data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +36 -0
- data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +51 -0
- data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +30 -0
- data/lib/couchbase/protostellar/generated.rb +9 -0
- data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
- data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
- data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
- data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
- data/lib/couchbase/protostellar/management.rb +24 -0
- data/lib/couchbase/protostellar/request.rb +78 -0
- data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
- data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
- data/lib/couchbase/protostellar/request_generator/admin/collection.rb +94 -0
- data/lib/couchbase/protostellar/request_generator/admin/query.rb +130 -0
- data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
- data/lib/couchbase/protostellar/request_generator/kv.rb +474 -0
- data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
- data/lib/couchbase/protostellar/request_generator/search.rb +387 -0
- data/lib/couchbase/protostellar/request_generator.rb +26 -0
- data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
- data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
- data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
- data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
- data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
- data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
- data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
- data/lib/couchbase/protostellar/response_converter.rb +26 -0
- data/lib/couchbase/protostellar/retry/action.rb +38 -0
- data/lib/couchbase/protostellar/retry/orchestrator.rb +60 -0
- data/lib/couchbase/protostellar/retry/reason.rb +67 -0
- data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
- data/lib/couchbase/protostellar/retry/strategies.rb +26 -0
- data/lib/couchbase/protostellar/retry.rb +28 -0
- data/lib/couchbase/protostellar/scope.rb +57 -0
- data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
- data/lib/couchbase/protostellar/timeouts.rb +83 -0
- data/lib/couchbase/protostellar.rb +29 -0
- data/lib/couchbase/query_options.rb +120 -0
- data/lib/couchbase/railtie.rb +45 -0
- data/lib/couchbase/raw_binary_transcoder.rb +37 -0
- data/lib/couchbase/raw_json_transcoder.rb +38 -0
- data/lib/couchbase/raw_string_transcoder.rb +40 -0
- data/lib/couchbase/scope.rb +256 -0
- data/lib/couchbase/search_options.rb +1622 -0
- data/lib/couchbase/subdoc.rb +290 -0
- data/lib/couchbase/transcoder_flags.rb +62 -0
- data/lib/couchbase/utils/generic_logger_adapter.rb +38 -0
- data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
- data/lib/couchbase/utils/time.rb +69 -0
- data/lib/couchbase/utils.rb +21 -0
- data/lib/couchbase/version.rb +23 -0
- data/lib/couchbase/view_options.rb +65 -0
- data/lib/couchbase.rb +28 -0
- data/lib/rails/generators/couchbase/config/config_generator.rb +27 -0
- metadata +191 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
# Copyright 2020-2021 Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "couchbase/scope"
|
16
|
+
require "couchbase/management/collection_manager"
|
17
|
+
require "couchbase/management/view_index_manager"
|
18
|
+
require "couchbase/options"
|
19
|
+
require "couchbase/view_options"
|
20
|
+
require "couchbase/diagnostics"
|
21
|
+
|
22
|
+
module Couchbase
|
23
|
+
# Provides access to a Couchbase bucket APIs
|
24
|
+
class Bucket
|
25
|
+
# @return [String] name of the bucket
|
26
|
+
attr_reader :name
|
27
|
+
|
28
|
+
alias inspect to_s
|
29
|
+
|
30
|
+
# @param [Couchbase::Backend] backend
|
31
|
+
def initialize(backend, name)
|
32
|
+
backend.open_bucket(name, true)
|
33
|
+
@backend = backend
|
34
|
+
@name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get default scope
|
38
|
+
#
|
39
|
+
# @return [Scope]
|
40
|
+
def default_scope
|
41
|
+
Scope.new(@backend, @name, "_default")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get a named scope
|
45
|
+
#
|
46
|
+
# @param [String] scope_name name of the scope
|
47
|
+
#
|
48
|
+
# @return [Scope]
|
49
|
+
def scope(scope_name)
|
50
|
+
Scope.new(@backend, @name, scope_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Opens the named collection in the default scope of the bucket
|
54
|
+
#
|
55
|
+
# @param [String] collection_name name of the collection
|
56
|
+
#
|
57
|
+
# @return [Collection]
|
58
|
+
def collection(collection_name)
|
59
|
+
default_scope.collection(collection_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Opens the default collection for this bucket
|
63
|
+
#
|
64
|
+
# @return [Collection]
|
65
|
+
def default_collection
|
66
|
+
Collection.new(@backend, @name, "_default", "_default")
|
67
|
+
end
|
68
|
+
|
69
|
+
# Performs query to view index.
|
70
|
+
#
|
71
|
+
# @param [String] design_document_name name of the design document
|
72
|
+
# @param [String] view_name name of the view to query
|
73
|
+
# @param [Options::View] options
|
74
|
+
#
|
75
|
+
# @example Make sure the view engine catch up with all mutations and return keys starting from +["random_brewery:"]+
|
76
|
+
# bucket.view_query("beer", "brewery_beers",
|
77
|
+
# Options::View(
|
78
|
+
# start_key: ["random_brewery:"],
|
79
|
+
# scan_consistency: :request_plus
|
80
|
+
# ))
|
81
|
+
#
|
82
|
+
# @return [ViewResult]
|
83
|
+
def view_query(design_document_name, view_name, options = Options::View::DEFAULT)
|
84
|
+
resp = @backend.document_view(@name, design_document_name, view_name, options.namespace, options.to_backend)
|
85
|
+
ViewResult.new do |res|
|
86
|
+
res.meta_data = ViewMetaData.new do |meta|
|
87
|
+
meta.total_rows = resp[:meta][:total_rows]
|
88
|
+
meta.debug_info = resp[:meta][:debug_info]
|
89
|
+
end
|
90
|
+
res.rows = resp[:rows].map do |entry|
|
91
|
+
ViewRow.new do |row|
|
92
|
+
row.id = entry[:id] if entry.key?(:id)
|
93
|
+
row.key = JSON.parse(entry[:key])
|
94
|
+
row.value = JSON.parse(entry[:value])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Management::CollectionManager]
|
101
|
+
def collections
|
102
|
+
Management::CollectionManager.new(@backend, @name)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Management::ViewIndexManager]
|
106
|
+
def view_indexes
|
107
|
+
Management::ViewIndexManager.new(@backend, @name)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Performs application-level ping requests against services in the couchbase cluster
|
111
|
+
#
|
112
|
+
# @param [Options::Ping] options
|
113
|
+
#
|
114
|
+
# @return [PingResult]
|
115
|
+
def ping(options = Options::Ping::DEFAULT)
|
116
|
+
resp = @backend.ping(@name, options.to_backend)
|
117
|
+
PingResult.new do |res|
|
118
|
+
res.version = resp[:version]
|
119
|
+
res.id = resp[:id]
|
120
|
+
res.sdk = resp[:sdk]
|
121
|
+
resp[:services].each do |type, svcs|
|
122
|
+
res.services[type] = svcs.map do |svc|
|
123
|
+
PingResult::ServiceInfo.new do |info|
|
124
|
+
info.id = svc[:id]
|
125
|
+
info.state = svc[:state]
|
126
|
+
info.latency = svc[:latency]
|
127
|
+
info.remote = svc[:remote]
|
128
|
+
info.local = svc[:local]
|
129
|
+
info.error = svc[:error]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @api private
|
137
|
+
# TODO: deprecate in 3.1
|
138
|
+
PingOptions = ::Couchbase::Options::Ping
|
139
|
+
|
140
|
+
# @api private
|
141
|
+
# TODO: deprecate in 3.1
|
142
|
+
ViewOptions = ::Couchbase::Options::View
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,460 @@
|
|
1
|
+
# Copyright 2020-2021 Couchbase, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "couchbase/configuration"
|
16
|
+
require "couchbase/authenticator"
|
17
|
+
require "couchbase/bucket"
|
18
|
+
require "couchbase/cluster_registry"
|
19
|
+
|
20
|
+
require "couchbase/management"
|
21
|
+
require "couchbase/options"
|
22
|
+
|
23
|
+
require "couchbase/search_options"
|
24
|
+
require "couchbase/query_options"
|
25
|
+
require "couchbase/analytics_options"
|
26
|
+
require "couchbase/diagnostics"
|
27
|
+
|
28
|
+
require "couchbase/protostellar"
|
29
|
+
|
30
|
+
module Couchbase
|
31
|
+
# The main entry point when connecting to a Couchbase cluster.
|
32
|
+
class Cluster
|
33
|
+
alias inspect to_s
|
34
|
+
|
35
|
+
# Connect to the Couchbase cluster
|
36
|
+
#
|
37
|
+
# @overload connect(connection_string_or_config, options)
|
38
|
+
# @param [String, Configuration] connection_string_or_config connection string used to locate the Couchbase Cluster
|
39
|
+
# @param [Options::Cluster] options custom options when creating the cluster connection
|
40
|
+
#
|
41
|
+
# @overload connect(connection_string_or_config, username, password, options)
|
42
|
+
# Shortcut for {PasswordAuthenticator}
|
43
|
+
# @param [String] connection_string_or_config connection string used to locate the Couchbase Cluster
|
44
|
+
# @param [String] username name of the user
|
45
|
+
# @param [String] password password of the user
|
46
|
+
# @param [Options::Cluster, nil] options custom options when creating the cluster connection
|
47
|
+
#
|
48
|
+
# @example Explicitly create options object and initialize PasswordAuthenticator internally
|
49
|
+
# options = Cluster::ClusterOptions.new
|
50
|
+
# options.authenticate("Administrator", "password")
|
51
|
+
# Cluster.connect("couchbase://localhost", options)
|
52
|
+
#
|
53
|
+
# @example Pass authenticator object to Options
|
54
|
+
# Cluster.connect("couchbase://localhost",
|
55
|
+
# Options::Cluster(authenticator: PasswordAuthenticator.new("Administrator", "password")))
|
56
|
+
#
|
57
|
+
# @example Shorter version, more useful for interactive sessions
|
58
|
+
# Cluster.connect("couchbase://localhost", "Administrator", "password")
|
59
|
+
#
|
60
|
+
# @example Authentication with TLS client certificate (note +couchbases://+ schema)
|
61
|
+
# Cluster.connect("couchbases://localhost?trust_certificate=/tmp/ca.pem",
|
62
|
+
# Options::Cluster(authenticator: CertificateAuthenticator.new("/tmp/certificate.pem", "/tmp/private.key")))
|
63
|
+
#
|
64
|
+
# @see https://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html
|
65
|
+
#
|
66
|
+
# @note The +couchbase2://+ scheme is currently at stability _uncommitted_
|
67
|
+
#
|
68
|
+
# @return [Cluster]
|
69
|
+
def self.connect(connection_string_or_config, *options)
|
70
|
+
connection_string = if connection_string_or_config.is_a?(Configuration)
|
71
|
+
connection_string_or_config.connection_string
|
72
|
+
else
|
73
|
+
connection_string_or_config
|
74
|
+
end
|
75
|
+
if connection_string =~ /\Acouchbases?:\/\/.*\z/i || !connection_string.include?("://")
|
76
|
+
Cluster.new(connection_string_or_config, *options)
|
77
|
+
else
|
78
|
+
ClusterRegistry.instance.connect(connection_string_or_config, *options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns an instance of the {Bucket}
|
83
|
+
#
|
84
|
+
# @param [String] name name of the bucket
|
85
|
+
#
|
86
|
+
# @return [Bucket]
|
87
|
+
def bucket(name)
|
88
|
+
Bucket.new(@backend, name)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Performs a query against the query (N1QL) services
|
92
|
+
#
|
93
|
+
# @param [String] statement the N1QL query statement
|
94
|
+
# @param [Options::Query] options the custom options for this query
|
95
|
+
#
|
96
|
+
# @example Select first ten hotels from travel sample dataset
|
97
|
+
# cluster.query("SELECT * FROM `travel-sample` WHERE type = $type LIMIT 10",
|
98
|
+
# Options::Query(named_parameters: {type: "hotel"}, metrics: true))
|
99
|
+
#
|
100
|
+
# @example Execute query with consistency requirement. Make sure that the index is in sync with selected mutation
|
101
|
+
# res = collection.upsert("user:42", {
|
102
|
+
# "name" => "Brass Doorknob",
|
103
|
+
# "email" => "brass.doorknob@example.com",
|
104
|
+
# })
|
105
|
+
# cluster.query("SELECT name, email FROM `mybucket`",
|
106
|
+
# Options::Query(consistent_with: MutationState.new(res.mutation_token)))
|
107
|
+
#
|
108
|
+
# @return [QueryResult]
|
109
|
+
def query(statement, options = Options::Query::DEFAULT)
|
110
|
+
resp = @backend.document_query(statement, options.to_backend)
|
111
|
+
|
112
|
+
QueryResult.new do |res|
|
113
|
+
res.meta_data = QueryMetaData.new do |meta|
|
114
|
+
meta.status = resp[:meta][:status]
|
115
|
+
meta.request_id = resp[:meta][:request_id]
|
116
|
+
meta.client_context_id = resp[:meta][:client_context_id]
|
117
|
+
meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
|
118
|
+
meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
|
119
|
+
meta.metrics = QueryMetrics.new do |metrics|
|
120
|
+
if resp[:meta][:metrics]
|
121
|
+
metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
|
122
|
+
metrics.execution_time = resp[:meta][:metrics][:execution_time]
|
123
|
+
metrics.sort_count = resp[:meta][:metrics][:sort_count]
|
124
|
+
metrics.result_count = resp[:meta][:metrics][:result_count]
|
125
|
+
metrics.result_size = resp[:meta][:metrics][:result_size]
|
126
|
+
metrics.mutation_count = resp[:meta][:metrics][:mutation_count]
|
127
|
+
metrics.error_count = resp[:meta][:metrics][:error_count]
|
128
|
+
metrics.warning_count = resp[:meta][:metrics][:warning_count]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
meta.warnings = resp[:warnings].map { |warn| QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
|
132
|
+
end
|
133
|
+
res.instance_variable_set(:@rows, resp[:rows])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Performs an analytics query
|
138
|
+
#
|
139
|
+
# @param [String] statement the N1QL query statement
|
140
|
+
# @param [Options::Analytics] options the custom options for this query
|
141
|
+
#
|
142
|
+
# @example Select name of the given user
|
143
|
+
# cluster.analytics_query("SELECT u.name AS uname FROM GleambookUsers u WHERE u.id = $user_id ",
|
144
|
+
# Options::Analytics(named_parameters: {user_id: 2}))
|
145
|
+
#
|
146
|
+
# @return [AnalyticsResult]
|
147
|
+
def analytics_query(statement, options = Options::Analytics::DEFAULT)
|
148
|
+
resp = @backend.document_analytics(statement, options.to_backend)
|
149
|
+
|
150
|
+
AnalyticsResult.new do |res|
|
151
|
+
res.transcoder = options.transcoder
|
152
|
+
res.meta_data = AnalyticsMetaData.new do |meta|
|
153
|
+
meta.status = resp[:meta][:status]
|
154
|
+
meta.request_id = resp[:meta][:request_id]
|
155
|
+
meta.client_context_id = resp[:meta][:client_context_id]
|
156
|
+
meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
|
157
|
+
meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
|
158
|
+
meta.metrics = AnalyticsMetrics.new do |metrics|
|
159
|
+
if resp[:meta][:metrics]
|
160
|
+
metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
|
161
|
+
metrics.execution_time = resp[:meta][:metrics][:execution_time]
|
162
|
+
metrics.result_count = resp[:meta][:metrics][:result_count]
|
163
|
+
metrics.result_size = resp[:meta][:metrics][:result_size]
|
164
|
+
metrics.error_count = resp[:meta][:metrics][:error_count]
|
165
|
+
metrics.warning_count = resp[:meta][:metrics][:warning_count]
|
166
|
+
metrics.processed_objects = resp[:meta][:metrics][:processed_objects]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
res[:warnings] = resp[:warnings].map { |warn| AnalyticsWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
|
170
|
+
end
|
171
|
+
res.instance_variable_set(:@rows, resp[:rows])
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Performs a Full Text Search (FTS) query
|
176
|
+
#
|
177
|
+
# @param [String] index_name the name of the search index
|
178
|
+
# @param [SearchQuery] query the query tree
|
179
|
+
# @param [Options::Search] options the custom options for this search query
|
180
|
+
#
|
181
|
+
# @example Return first 10 results of "hop beer" query and request highlighting
|
182
|
+
# cluster.search_query("beer_index", Cluster::SearchQuery.match_phrase("hop beer"),
|
183
|
+
# Options::Search(
|
184
|
+
# limit: 10,
|
185
|
+
# fields: %w[name],
|
186
|
+
# highlight_style: :html,
|
187
|
+
# highlight_fields: %w[name description]
|
188
|
+
# ))
|
189
|
+
#
|
190
|
+
# @return [SearchResult]
|
191
|
+
def search_query(index_name, query, options = Options::Search::DEFAULT)
|
192
|
+
resp = @backend.document_search(nil, nil, index_name, JSON.generate(query), {}, options.to_backend)
|
193
|
+
convert_search_result(resp, options)
|
194
|
+
end
|
195
|
+
|
196
|
+
# Performs a request against the Full Text Search (FTS) service.
|
197
|
+
#
|
198
|
+
# @param [String] index_name the name of the search index
|
199
|
+
# @param [SearchRequest] search_request the request
|
200
|
+
# @param [Options::Search] options the custom options for this search request
|
201
|
+
#
|
202
|
+
# @return [SearchResult]
|
203
|
+
def search(index_name, search_request, options = Options::Search::DEFAULT)
|
204
|
+
encoded_query, encoded_req = search_request.to_backend
|
205
|
+
resp = @backend.document_search(nil, nil, index_name, encoded_query, encoded_req, options.to_backend(show_request: false))
|
206
|
+
convert_search_result(resp, options)
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return [Management::UserManager]
|
210
|
+
def users
|
211
|
+
Management::UserManager.new(@backend)
|
212
|
+
end
|
213
|
+
|
214
|
+
# @return [Management::BucketManager]
|
215
|
+
def buckets
|
216
|
+
Management::BucketManager.new(@backend)
|
217
|
+
end
|
218
|
+
|
219
|
+
# @return [Management::QueryIndexManager]
|
220
|
+
def query_indexes
|
221
|
+
Management::QueryIndexManager.new(@backend)
|
222
|
+
end
|
223
|
+
|
224
|
+
# @return [Management::AnalyticsIndexManager]
|
225
|
+
def analytics_indexes
|
226
|
+
Management::AnalyticsIndexManager.new(@backend)
|
227
|
+
end
|
228
|
+
|
229
|
+
# @return [Management::SearchIndexManager]
|
230
|
+
def search_indexes
|
231
|
+
Management::SearchIndexManager.new(@backend)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Closes all connections to services and free allocated resources
|
235
|
+
#
|
236
|
+
# @return [void]
|
237
|
+
def disconnect
|
238
|
+
@backend.close
|
239
|
+
end
|
240
|
+
|
241
|
+
# Creates diagnostic report that can be used to determine the health of the network connections.
|
242
|
+
#
|
243
|
+
# It does not proactively perform any I/O against the network
|
244
|
+
#
|
245
|
+
# @param [Options::Diagnostics] options
|
246
|
+
#
|
247
|
+
# @return [DiagnosticsResult]
|
248
|
+
def diagnostics(options = Options::Diagnostics::DEFAULT)
|
249
|
+
resp = @backend.diagnostics(options.report_id)
|
250
|
+
DiagnosticsResult.new do |res|
|
251
|
+
res.version = resp[:version]
|
252
|
+
res.id = resp[:id]
|
253
|
+
res.sdk = resp[:sdk]
|
254
|
+
resp[:services].each do |type, svcs|
|
255
|
+
res.services[type] = svcs.map do |svc|
|
256
|
+
DiagnosticsResult::ServiceInfo.new do |info|
|
257
|
+
info.id = svc[:id]
|
258
|
+
info.state = svc[:state]
|
259
|
+
info.last_activity_us = svc[:last_activity_us]
|
260
|
+
info.remote = svc[:remote]
|
261
|
+
info.local = svc[:local]
|
262
|
+
info.details = svc[:details]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Performs application-level ping requests against services in the couchbase cluster
|
270
|
+
#
|
271
|
+
# @param [Options::Ping] options
|
272
|
+
#
|
273
|
+
# @return [PingResult]
|
274
|
+
def ping(options = Options::Ping::DEFAULT)
|
275
|
+
resp = @backend.ping(nil, options.to_backend)
|
276
|
+
PingResult.new do |res|
|
277
|
+
res.version = resp[:version]
|
278
|
+
res.id = resp[:id]
|
279
|
+
res.sdk = resp[:sdk]
|
280
|
+
resp[:services].each do |type, svcs|
|
281
|
+
res.services[type] = svcs.map do |svc|
|
282
|
+
PingResult::ServiceInfo.new do |info|
|
283
|
+
info.id = svc[:id]
|
284
|
+
info.state = svc[:state]
|
285
|
+
info.latency = svc[:latency]
|
286
|
+
info.remote = svc[:remote]
|
287
|
+
info.local = svc[:local]
|
288
|
+
info.error = svc[:error]
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
private
|
296
|
+
|
297
|
+
# Initialize {Cluster} object
|
298
|
+
#
|
299
|
+
# @overload new(connection_string, options)
|
300
|
+
# @param [String] connection_string connection string used to locate the Couchbase Cluster
|
301
|
+
# @param [Options::Cluster] options custom options when creating the cluster connection
|
302
|
+
#
|
303
|
+
# @overload new(connection_string, username, password, options)
|
304
|
+
# Shortcut for {PasswordAuthenticator}
|
305
|
+
# @param [String] connection_string connection string used to locate the Couchbase Cluster
|
306
|
+
# @param [String] username name of the user
|
307
|
+
# @param [String] password password of the user
|
308
|
+
# @param [Options::Cluster, nil] options custom options when creating the cluster connection
|
309
|
+
#
|
310
|
+
# @overload new(configuration)
|
311
|
+
# @param [Configuration] configuration configuration object
|
312
|
+
def initialize(connection_string, *args)
|
313
|
+
credentials = {}
|
314
|
+
open_options = {}
|
315
|
+
|
316
|
+
if connection_string.is_a?(Configuration)
|
317
|
+
options = connection_string
|
318
|
+
connection_string = options.connection_string
|
319
|
+
credentials[:username] = options.username
|
320
|
+
credentials[:password] = options.password
|
321
|
+
raise ArgumentError, "missing connection_string" unless connection_string
|
322
|
+
raise ArgumentError, "missing username" unless credentials[:username]
|
323
|
+
raise ArgumentError, "missing password" unless credentials[:password]
|
324
|
+
else
|
325
|
+
options = args.shift
|
326
|
+
case options
|
327
|
+
when String
|
328
|
+
credentials[:username] = options
|
329
|
+
credentials[:password] = args.shift
|
330
|
+
raise ArgumentError, "missing username" unless credentials[:username]
|
331
|
+
raise ArgumentError, "missing password" unless credentials[:password]
|
332
|
+
when Options::Cluster
|
333
|
+
open_options = options&.to_backend || {}
|
334
|
+
authenticator = options&.authenticator
|
335
|
+
case authenticator
|
336
|
+
when PasswordAuthenticator
|
337
|
+
credentials[:username] = authenticator&.username
|
338
|
+
raise ArgumentError, "missing username" unless credentials[:username]
|
339
|
+
|
340
|
+
credentials[:password] = authenticator&.password
|
341
|
+
raise ArgumentError, "missing password" unless credentials[:password]
|
342
|
+
|
343
|
+
open_options[:allowed_sasl_mechanisms] = authenticator&.allowed_sasl_mechanisms
|
344
|
+
when CertificateAuthenticator
|
345
|
+
credentials[:certificate_path] = authenticator&.certificate_path
|
346
|
+
raise ArgumentError, "missing certificate path" unless credentials[:certificate_path]
|
347
|
+
|
348
|
+
credentials[:key_path] = authenticator&.key_path
|
349
|
+
raise ArgumentError, "missing key path" unless credentials[:key_path]
|
350
|
+
|
351
|
+
else
|
352
|
+
raise ArgumentError, "options must have authenticator configured"
|
353
|
+
end
|
354
|
+
else
|
355
|
+
raise ArgumentError, "unexpected second argument, have to be String or ClusterOptions"
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
@backend = Backend.new
|
360
|
+
@backend.open(connection_string, credentials, open_options)
|
361
|
+
end
|
362
|
+
|
363
|
+
# @api private
|
364
|
+
def convert_search_result(resp, options)
|
365
|
+
SearchResult.new do |res|
|
366
|
+
res.meta_data = SearchMetaData.new do |meta|
|
367
|
+
meta.metrics.max_score = resp[:meta_data][:metrics][:max_score]
|
368
|
+
meta.metrics.error_partition_count = resp[:meta_data][:metrics][:error_partition_count]
|
369
|
+
meta.metrics.success_partition_count = resp[:meta_data][:metrics][:success_partition_count]
|
370
|
+
meta.metrics.took = resp[:meta_data][:metrics][:took]
|
371
|
+
meta.metrics.total_rows = resp[:meta_data][:metrics][:total_rows]
|
372
|
+
meta.errors = resp[:meta_data][:errors]
|
373
|
+
end
|
374
|
+
res.rows = resp[:rows].map do |r|
|
375
|
+
SearchRow.new do |row|
|
376
|
+
row.transcoder = options.transcoder
|
377
|
+
row.index = r[:index]
|
378
|
+
row.id = r[:id]
|
379
|
+
row.score = r[:score]
|
380
|
+
row.fragments = r[:fragments]
|
381
|
+
unless r[:locations].empty?
|
382
|
+
row.locations = SearchRowLocations.new(
|
383
|
+
r[:locations].map do |loc|
|
384
|
+
SearchRowLocation.new do |location|
|
385
|
+
location.field = loc[:field]
|
386
|
+
location.term = loc[:term]
|
387
|
+
location.position = loc[:position]
|
388
|
+
location.start_offset = loc[:start_offset]
|
389
|
+
location.end_offset = loc[:end_offset]
|
390
|
+
location.array_positions = loc[:array_positions]
|
391
|
+
end
|
392
|
+
end
|
393
|
+
)
|
394
|
+
end
|
395
|
+
row.instance_variable_set(:@fields, r[:fields])
|
396
|
+
row.explanation = JSON.parse(r[:explanation]) if r[:explanation]
|
397
|
+
end
|
398
|
+
end
|
399
|
+
if resp[:facets]
|
400
|
+
res.facets = resp[:facets].each_with_object({}) do |(k, v), o|
|
401
|
+
facet = case options.facets[k]
|
402
|
+
when SearchFacet::SearchFacetTerm
|
403
|
+
SearchFacetResult::TermFacetResult.new do |f|
|
404
|
+
f.terms =
|
405
|
+
if v[:terms]
|
406
|
+
v[:terms].map do |t|
|
407
|
+
SearchFacetResult::TermFacetResult::TermFacet.new(t[:term], t[:count])
|
408
|
+
end
|
409
|
+
else
|
410
|
+
[]
|
411
|
+
end
|
412
|
+
end
|
413
|
+
when SearchFacet::SearchFacetDateRange
|
414
|
+
SearchFacetResult::DateRangeFacetResult.new do |f|
|
415
|
+
f.date_ranges =
|
416
|
+
if v[:date_ranges]
|
417
|
+
v[:date_ranges].map do |r|
|
418
|
+
SearchFacetResult::DateRangeFacetResult::DateRangeFacet.new(r[:name], r[:count], r[:start_time], r[:end_time])
|
419
|
+
end
|
420
|
+
else
|
421
|
+
[]
|
422
|
+
end
|
423
|
+
end
|
424
|
+
when SearchFacet::SearchFacetNumericRange
|
425
|
+
SearchFacetResult::NumericRangeFacetResult.new do |f|
|
426
|
+
f.numeric_ranges =
|
427
|
+
if v[:numeric_ranges]
|
428
|
+
v[:numeric_ranges].map do |r|
|
429
|
+
SearchFacetResult::NumericRangeFacetResult::NumericRangeFacet.new(r[:name], r[:count], r[:min], r[:max])
|
430
|
+
end
|
431
|
+
else
|
432
|
+
[]
|
433
|
+
end
|
434
|
+
end
|
435
|
+
else
|
436
|
+
next # ignore unknown facet result
|
437
|
+
end
|
438
|
+
facet.name = v[:name]
|
439
|
+
facet.field = v[:field]
|
440
|
+
facet.total = v[:total]
|
441
|
+
facet.missing = v[:missing]
|
442
|
+
facet.other = v[:other]
|
443
|
+
o[k] = facet
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
# @api private
|
450
|
+
ClusterOptions = ::Couchbase::Options::Cluster
|
451
|
+
# @api private
|
452
|
+
DiagnosticsOptions = ::Couchbase::Options::Diagnostics
|
453
|
+
# @api private
|
454
|
+
AnalyticsOptions = ::Couchbase::Options::Analytics
|
455
|
+
# @api private
|
456
|
+
QueryOptions = ::Couchbase::Options::Query
|
457
|
+
# @api private
|
458
|
+
SearchOptions = ::Couchbase::Options::Search
|
459
|
+
end
|
460
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 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
|
+
require "singleton"
|
18
|
+
|
19
|
+
require "couchbase/errors"
|
20
|
+
|
21
|
+
module Couchbase
|
22
|
+
class ClusterRegistry
|
23
|
+
include Singleton
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@handlers = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def connect(connection_string_or_config, *options)
|
30
|
+
connection_string = if connection_string_or_config.is_a?(Configuration)
|
31
|
+
connection_string_or_config.connection_string
|
32
|
+
else
|
33
|
+
connection_string_or_config
|
34
|
+
end
|
35
|
+
@handlers.each do |regexp, cluster_class|
|
36
|
+
return cluster_class.connect(connection_string_or_config, *options) if regexp.match?(connection_string)
|
37
|
+
end
|
38
|
+
raise(Error::FeatureNotAvailable, "Connection string '#{connection_string}' not supported.")
|
39
|
+
end
|
40
|
+
|
41
|
+
def register_connection_handler(regexp, cluster_class)
|
42
|
+
@handlers[regexp] = cluster_class
|
43
|
+
end
|
44
|
+
|
45
|
+
def deregister_connection_handler(regexp)
|
46
|
+
@handlers.delete(regexp)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|