couchbase 3.9.0-aarch64-linux-musl

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 (149) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +202 -0
  3. data/README.md +154 -0
  4. data/ext/extconf.rb +0 -0
  5. data/lib/active_support/cache/couchbase_store.rb +407 -0
  6. data/lib/couchbase/3.2/libcouchbase.so +0 -0
  7. data/lib/couchbase/3.3/libcouchbase.so +0 -0
  8. data/lib/couchbase/3.4/libcouchbase.so +0 -0
  9. data/lib/couchbase/4.0/libcouchbase.so +0 -0
  10. data/lib/couchbase/analytics_options.rb +109 -0
  11. data/lib/couchbase/authenticator.rb +80 -0
  12. data/lib/couchbase/binary_collection.rb +145 -0
  13. data/lib/couchbase/binary_collection_options.rb +26 -0
  14. data/lib/couchbase/bucket.rb +173 -0
  15. data/lib/couchbase/cluster.rb +555 -0
  16. data/lib/couchbase/cluster_registry.rb +49 -0
  17. data/lib/couchbase/collection.rb +770 -0
  18. data/lib/couchbase/collection_options.rb +401 -0
  19. data/lib/couchbase/config_profiles.rb +57 -0
  20. data/lib/couchbase/configuration.rb +58 -0
  21. data/lib/couchbase/datastructures/couchbase_list.rb +192 -0
  22. data/lib/couchbase/datastructures/couchbase_map.rb +231 -0
  23. data/lib/couchbase/datastructures/couchbase_queue.rb +161 -0
  24. data/lib/couchbase/datastructures/couchbase_set.rb +145 -0
  25. data/lib/couchbase/datastructures.rb +26 -0
  26. data/lib/couchbase/deprecations.rb +61 -0
  27. data/lib/couchbase/diagnostics.rb +183 -0
  28. data/lib/couchbase/errors.rb +438 -0
  29. data/lib/couchbase/fork_hooks.rb +41 -0
  30. data/lib/couchbase/get_replica_strategy.rb +89 -0
  31. data/lib/couchbase/json_transcoder.rb +41 -0
  32. data/lib/couchbase/key_value_scan.rb +119 -0
  33. data/lib/couchbase/libcouchbase.rb +6 -0
  34. data/lib/couchbase/logger.rb +87 -0
  35. data/lib/couchbase/management/analytics_index_manager.rb +1160 -0
  36. data/lib/couchbase/management/bucket_manager.rb +479 -0
  37. data/lib/couchbase/management/collection_manager.rb +515 -0
  38. data/lib/couchbase/management/collection_query_index_manager.rb +247 -0
  39. data/lib/couchbase/management/query_index_manager.rb +671 -0
  40. data/lib/couchbase/management/scope_search_index_manager.rb +267 -0
  41. data/lib/couchbase/management/search_index_manager.rb +649 -0
  42. data/lib/couchbase/management/user_manager.rb +639 -0
  43. data/lib/couchbase/management/view_index_manager.rb +332 -0
  44. data/lib/couchbase/management.rb +31 -0
  45. data/lib/couchbase/metrics/logging_meter.rb +108 -0
  46. data/lib/couchbase/metrics/logging_value_recorder.rb +50 -0
  47. data/lib/couchbase/metrics/meter.rb +27 -0
  48. data/lib/couchbase/metrics/noop_meter.rb +30 -0
  49. data/lib/couchbase/metrics/noop_value_recorder.rb +27 -0
  50. data/lib/couchbase/metrics/value_recorder.rb +25 -0
  51. data/lib/couchbase/mutation_state.rb +65 -0
  52. data/lib/couchbase/options.rb +3097 -0
  53. data/lib/couchbase/protostellar/binary_collection.rb +55 -0
  54. data/lib/couchbase/protostellar/bucket.rb +59 -0
  55. data/lib/couchbase/protostellar/client.rb +97 -0
  56. data/lib/couchbase/protostellar/cluster.rb +182 -0
  57. data/lib/couchbase/protostellar/collection.rb +156 -0
  58. data/lib/couchbase/protostellar/connect_options.rb +63 -0
  59. data/lib/couchbase/protostellar/error_handling.rb +204 -0
  60. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_pb.rb +54 -0
  61. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_services_pb.rb +51 -0
  62. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +42 -0
  63. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +51 -0
  64. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +38 -0
  65. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +52 -0
  66. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +42 -0
  67. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +55 -0
  68. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +51 -0
  69. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +67 -0
  70. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +31 -0
  71. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +40 -0
  72. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +51 -0
  73. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +54 -0
  74. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_pb.rb +46 -0
  75. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_services_pb.rb +56 -0
  76. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +74 -0
  77. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +93 -0
  78. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +35 -0
  79. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +40 -0
  80. data/lib/couchbase/protostellar/generated/routing/v2/routing_pb.rb +26 -0
  81. data/lib/couchbase/protostellar/generated/routing/v2/routing_services_pb.rb +43 -0
  82. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +78 -0
  83. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +41 -0
  84. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +36 -0
  85. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +66 -0
  86. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +30 -0
  87. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +39 -0
  88. data/lib/couchbase/protostellar/generated.rb +9 -0
  89. data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
  90. data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
  91. data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
  92. data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
  93. data/lib/couchbase/protostellar/management.rb +24 -0
  94. data/lib/couchbase/protostellar/request.rb +79 -0
  95. data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
  96. data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
  97. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +96 -0
  98. data/lib/couchbase/protostellar/request_generator/admin/query.rb +132 -0
  99. data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
  100. data/lib/couchbase/protostellar/request_generator/kv.rb +488 -0
  101. data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
  102. data/lib/couchbase/protostellar/request_generator/search.rb +403 -0
  103. data/lib/couchbase/protostellar/request_generator.rb +26 -0
  104. data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
  105. data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
  106. data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
  107. data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
  108. data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
  109. data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
  110. data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
  111. data/lib/couchbase/protostellar/response_converter.rb +26 -0
  112. data/lib/couchbase/protostellar/retry/action.rb +38 -0
  113. data/lib/couchbase/protostellar/retry/orchestrator.rb +61 -0
  114. data/lib/couchbase/protostellar/retry/reason.rb +67 -0
  115. data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
  116. data/lib/couchbase/protostellar/retry/strategies/fail_fast.rb +33 -0
  117. data/lib/couchbase/protostellar/retry/strategies.rb +27 -0
  118. data/lib/couchbase/protostellar/retry.rb +28 -0
  119. data/lib/couchbase/protostellar/scope.rb +61 -0
  120. data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
  121. data/lib/couchbase/protostellar/timeouts.rb +83 -0
  122. data/lib/couchbase/protostellar.rb +29 -0
  123. data/lib/couchbase/query_options.rb +122 -0
  124. data/lib/couchbase/railtie.rb +47 -0
  125. data/lib/couchbase/raw_binary_transcoder.rb +39 -0
  126. data/lib/couchbase/raw_json_transcoder.rb +40 -0
  127. data/lib/couchbase/raw_string_transcoder.rb +42 -0
  128. data/lib/couchbase/scope.rb +272 -0
  129. data/lib/couchbase/search_options.rb +1744 -0
  130. data/lib/couchbase/subdoc.rb +293 -0
  131. data/lib/couchbase/tracing/noop_span.rb +29 -0
  132. data/lib/couchbase/tracing/noop_tracer.rb +29 -0
  133. data/lib/couchbase/tracing/request_span.rb +34 -0
  134. data/lib/couchbase/tracing/request_tracer.rb +28 -0
  135. data/lib/couchbase/tracing/threshold_logging_span.rb +112 -0
  136. data/lib/couchbase/tracing/threshold_logging_tracer.rb +231 -0
  137. data/lib/couchbase/transcoder_flags.rb +64 -0
  138. data/lib/couchbase/utils/generic_logger_adapter.rb +40 -0
  139. data/lib/couchbase/utils/hdr_histogram.rb +55 -0
  140. data/lib/couchbase/utils/observability.rb +263 -0
  141. data/lib/couchbase/utils/observability_constants.rb +200 -0
  142. data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
  143. data/lib/couchbase/utils/time.rb +71 -0
  144. data/lib/couchbase/utils.rb +23 -0
  145. data/lib/couchbase/version.rb +25 -0
  146. data/lib/couchbase/view_options.rb +67 -0
  147. data/lib/couchbase.rb +32 -0
  148. data/lib/rails/generators/couchbase/config/config_generator.rb +29 -0
  149. metadata +228 -0
@@ -0,0 +1,555 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2020-2021 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 "couchbase/configuration"
18
+ require "couchbase/authenticator"
19
+ require "couchbase/bucket"
20
+ require "couchbase/cluster_registry"
21
+
22
+ require "couchbase/management"
23
+ require "couchbase/options"
24
+
25
+ require "couchbase/search_options"
26
+ require "couchbase/query_options"
27
+ require "couchbase/analytics_options"
28
+ require "couchbase/diagnostics"
29
+
30
+ require "couchbase/protostellar"
31
+ require "couchbase/utils/observability"
32
+
33
+ require "couchbase/tracing/threshold_logging_tracer"
34
+ require "couchbase/tracing/noop_tracer"
35
+ require "couchbase/metrics/noop_meter"
36
+ require "couchbase/metrics/logging_meter"
37
+
38
+ module Couchbase
39
+ # The main entry point when connecting to a Couchbase cluster.
40
+ class Cluster
41
+ alias inspect to_s
42
+
43
+ # Connect to the Couchbase cluster
44
+ #
45
+ # @overload connect(connection_string_or_config, options)
46
+ # @param [String, Configuration] connection_string_or_config connection string used to locate the Couchbase Cluster
47
+ # @param [Options::Cluster] options custom options when creating the cluster connection
48
+ #
49
+ # @overload connect(connection_string_or_config, username, password, options)
50
+ # Shortcut for {PasswordAuthenticator}
51
+ # @param [String] connection_string_or_config connection string used to locate the Couchbase Cluster
52
+ # @param [String] username name of the user
53
+ # @param [String] password password of the user
54
+ # @param [Options::Cluster, nil] options custom options when creating the cluster connection
55
+ #
56
+ # @example Explicitly create options object and initialize PasswordAuthenticator internally
57
+ # options = Options::Cluster.new
58
+ # options.authenticate("Administrator", "password")
59
+ # Cluster.connect("couchbase://localhost", options)
60
+ #
61
+ # @example Pass authenticator object to Options
62
+ # Cluster.connect("couchbase://localhost",
63
+ # Options::Cluster(authenticator: PasswordAuthenticator.new("Administrator", "password")))
64
+ #
65
+ # @example Shorter version, more useful for interactive sessions
66
+ # Cluster.connect("couchbase://localhost", "Administrator", "password")
67
+ #
68
+ # @example Authentication with TLS client certificate (note +couchbases://+ schema)
69
+ # Cluster.connect("couchbases://localhost?trust_certificate=/tmp/ca.pem",
70
+ # Options::Cluster(authenticator: CertificateAuthenticator.new("/tmp/certificate.pem", "/tmp/private.key")))
71
+ #
72
+ # @see https://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html
73
+ #
74
+ # @note The +couchbase2://+ scheme is currently at stability _uncommitted_
75
+ #
76
+ # @return [Cluster]
77
+ def self.connect(connection_string_or_config, *options)
78
+ connection_string = if connection_string_or_config.is_a?(Configuration)
79
+ connection_string_or_config.connection_string
80
+ else
81
+ connection_string_or_config
82
+ end
83
+ if connection_string =~ /\Acouchbases?:\/\/.*\z/i || !connection_string.include?("://")
84
+ Cluster.new(connection_string_or_config, *options)
85
+ else
86
+ ClusterRegistry.instance.connect(connection_string_or_config, *options)
87
+ end
88
+ end
89
+
90
+ # Returns an instance of the {Bucket}
91
+ #
92
+ # @param [String] name name of the bucket
93
+ #
94
+ # @return [Bucket]
95
+ def bucket(name)
96
+ Bucket.new(@backend, name, @observability)
97
+ end
98
+
99
+ # Updates the authenticator used for this cluster connection
100
+ #
101
+ # @param [PasswordAuthenticator, CertificateAuthenticator, JWTAuthenticator] authenticator the new authenticator
102
+ def update_authenticator(authenticator)
103
+ credentials = {}
104
+
105
+ case authenticator
106
+ when PasswordAuthenticator
107
+ credentials[:username] = authenticator.username
108
+ raise ArgumentError, "missing username" unless credentials[:username]
109
+
110
+ credentials[:password] = authenticator.password
111
+ raise ArgumentError, "missing password" unless credentials[:password]
112
+
113
+ when CertificateAuthenticator
114
+ credentials[:certificate_path] = authenticator.certificate_path
115
+ raise ArgumentError, "missing certificate path" unless credentials[:certificate_path]
116
+
117
+ credentials[:key_path] = authenticator.key_path
118
+ raise ArgumentError, "missing key path" unless credentials[:key_path]
119
+
120
+ when JWTAuthenticator
121
+ credentials[:jwt] = authenticator.token
122
+ raise ArgumentError, "missing token" unless credentials[:jwt]
123
+
124
+ else
125
+ raise ArgumentError, "argument must be an authenticator"
126
+ end
127
+
128
+ @backend.update_credentials(credentials)
129
+ end
130
+
131
+ # Performs a query against the query (N1QL) services
132
+ #
133
+ # @param [String] statement the N1QL query statement
134
+ # @param [Options::Query] options the custom options for this query
135
+ #
136
+ # @example Select first ten hotels from travel sample dataset
137
+ # cluster.query("SELECT * FROM `travel-sample` WHERE type = $type LIMIT 10",
138
+ # Options::Query(named_parameters: {type: "hotel"}, metrics: true))
139
+ #
140
+ # @example Execute query with consistency requirement. Make sure that the index is in sync with selected mutation
141
+ # res = collection.upsert("user:42", {
142
+ # "name" => "Brass Doorknob",
143
+ # "email" => "brass.doorknob@example.com",
144
+ # })
145
+ # cluster.query("SELECT name, email FROM `mybucket`",
146
+ # Options::Query(consistent_with: MutationState.new(res.mutation_token)))
147
+ #
148
+ # @return [QueryResult]
149
+ def query(statement, options = Options::Query::DEFAULT)
150
+ @observability.record_operation(Observability::OP_QUERY, options.parent_span, self, :query) do |obs_handler|
151
+ obs_handler.add_query_statement(statement, options)
152
+
153
+ resp = @backend.document_query(statement, options.to_backend, obs_handler)
154
+
155
+ QueryResult.new do |res|
156
+ res.meta_data = QueryMetaData.new do |meta|
157
+ meta.status = resp[:meta][:status]
158
+ meta.request_id = resp[:meta][:request_id]
159
+ meta.client_context_id = resp[:meta][:client_context_id]
160
+ meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
161
+ meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
162
+ meta.metrics = QueryMetrics.new do |metrics|
163
+ if resp[:meta][:metrics]
164
+ metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
165
+ metrics.execution_time = resp[:meta][:metrics][:execution_time]
166
+ metrics.sort_count = resp[:meta][:metrics][:sort_count]
167
+ metrics.result_count = resp[:meta][:metrics][:result_count]
168
+ metrics.result_size = resp[:meta][:metrics][:result_size]
169
+ metrics.mutation_count = resp[:meta][:metrics][:mutation_count]
170
+ metrics.error_count = resp[:meta][:metrics][:error_count]
171
+ metrics.warning_count = resp[:meta][:metrics][:warning_count]
172
+ end
173
+ end
174
+ meta.warnings = resp[:warnings].map { |warn| QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
175
+ end
176
+ res.instance_variable_set(:@rows, resp[:rows])
177
+ end
178
+ end
179
+ end
180
+
181
+ # Performs an analytics query
182
+ #
183
+ # @param [String] statement the N1QL query statement
184
+ # @param [Options::Analytics] options the custom options for this query
185
+ #
186
+ # @example Select name of the given user
187
+ # cluster.analytics_query("SELECT u.name AS uname FROM GleambookUsers u WHERE u.id = $user_id ",
188
+ # Options::Analytics(named_parameters: {user_id: 2}))
189
+ #
190
+ # @return [AnalyticsResult]
191
+ def analytics_query(statement, options = Options::Analytics::DEFAULT)
192
+ @observability.record_operation(Observability::OP_ANALYTICS_QUERY, options.parent_span, self, :analytics) do |obs_handler|
193
+ obs_handler.add_query_statement(statement, options)
194
+
195
+ resp = @backend.document_analytics(statement, options.to_backend, obs_handler)
196
+
197
+ AnalyticsResult.new do |res|
198
+ res.transcoder = options.transcoder
199
+ res.meta_data = AnalyticsMetaData.new do |meta|
200
+ meta.status = resp[:meta][:status]
201
+ meta.request_id = resp[:meta][:request_id]
202
+ meta.client_context_id = resp[:meta][:client_context_id]
203
+ meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
204
+ meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
205
+ meta.metrics = AnalyticsMetrics.new do |metrics|
206
+ if resp[:meta][:metrics]
207
+ metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
208
+ metrics.execution_time = resp[:meta][:metrics][:execution_time]
209
+ metrics.result_count = resp[:meta][:metrics][:result_count]
210
+ metrics.result_size = resp[:meta][:metrics][:result_size]
211
+ metrics.error_count = resp[:meta][:metrics][:error_count]
212
+ metrics.warning_count = resp[:meta][:metrics][:warning_count]
213
+ metrics.processed_objects = resp[:meta][:metrics][:processed_objects]
214
+ end
215
+ end
216
+ res[:warnings] = resp[:warnings].map { |warn| AnalyticsWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
217
+ end
218
+ res.instance_variable_set(:@rows, resp[:rows])
219
+ end
220
+ end
221
+ end
222
+
223
+ # Performs a Full Text Search (FTS) query
224
+ #
225
+ # @param [String] index_name the name of the search index
226
+ # @param [SearchQuery] query the query tree
227
+ # @param [Options::Search] options the custom options for this search query
228
+ #
229
+ # @example Return first 10 results of "hop beer" query and request highlighting
230
+ # cluster.search_query("beer_index", Cluster::SearchQuery.match_phrase("hop beer"),
231
+ # Options::Search(
232
+ # limit: 10,
233
+ # fields: %w[name],
234
+ # highlight_style: :html,
235
+ # highlight_fields: %w[name description]
236
+ # ))
237
+ #
238
+ # @return [SearchResult]
239
+ def search_query(index_name, query, options = Options::Search::DEFAULT)
240
+ @observability.record_operation(Observability::OP_SEARCH_QUERY, options.parent_span, self, :search) do |obs_handler|
241
+ resp = @backend.document_search(nil, nil, index_name, JSON.generate(query), {}, options.to_backend, obs_handler)
242
+ convert_search_result(resp, options)
243
+ end
244
+ end
245
+
246
+ # Performs a request against the Full Text Search (FTS) service.
247
+ #
248
+ # @param [String] index_name the name of the search index
249
+ # @param [SearchRequest] search_request the request
250
+ # @param [Options::Search] options the custom options for this search request
251
+ #
252
+ # @return [SearchResult]
253
+ def search(index_name, search_request, options = Options::Search::DEFAULT)
254
+ @observability.record_operation(Observability::OP_SEARCH_QUERY, options.parent_span, self, :search) do |obs_handler|
255
+ encoded_query, encoded_req = search_request.to_backend
256
+ resp = @backend.document_search(nil, nil, index_name, encoded_query, encoded_req, options.to_backend(show_request: false),
257
+ obs_handler)
258
+ convert_search_result(resp, options)
259
+ end
260
+ end
261
+
262
+ # @return [Management::UserManager]
263
+ def users
264
+ Management::UserManager.new(@backend, @observability)
265
+ end
266
+
267
+ # @return [Management::BucketManager]
268
+ def buckets
269
+ Management::BucketManager.new(@backend, @observability)
270
+ end
271
+
272
+ # @return [Management::QueryIndexManager]
273
+ def query_indexes
274
+ Management::QueryIndexManager.new(@backend, @observability)
275
+ end
276
+
277
+ # @return [Management::AnalyticsIndexManager]
278
+ def analytics_indexes
279
+ Management::AnalyticsIndexManager.new(@backend, @observability)
280
+ end
281
+
282
+ # @return [Management::SearchIndexManager]
283
+ def search_indexes
284
+ Management::SearchIndexManager.new(@backend, @observability)
285
+ end
286
+
287
+ # Closes all connections to services and free allocated resources
288
+ #
289
+ # @return [void]
290
+ def disconnect
291
+ @backend.close
292
+ @observability.close
293
+ end
294
+
295
+ # Creates diagnostic report that can be used to determine the health of the network connections.
296
+ #
297
+ # It does not proactively perform any I/O against the network
298
+ #
299
+ # @param [Options::Diagnostics] options
300
+ #
301
+ # @return [DiagnosticsResult]
302
+ def diagnostics(options = Options::Diagnostics::DEFAULT)
303
+ resp = @backend.diagnostics(options.report_id)
304
+ DiagnosticsResult.new do |res|
305
+ res.version = resp[:version]
306
+ res.id = resp[:id]
307
+ res.sdk = resp[:sdk]
308
+ resp[:services].each do |type, svcs|
309
+ res.services[type] = svcs.map do |svc|
310
+ DiagnosticsResult::ServiceInfo.new do |info|
311
+ info.id = svc[:id]
312
+ info.state = svc[:state]
313
+ info.last_activity_us = svc[:last_activity_us]
314
+ info.remote = svc[:remote]
315
+ info.local = svc[:local]
316
+ info.details = svc[:details]
317
+ end
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ # Performs application-level ping requests against services in the couchbase cluster
324
+ #
325
+ # @param [Options::Ping] options
326
+ #
327
+ # @return [PingResult]
328
+ def ping(options = Options::Ping::DEFAULT)
329
+ @observability.record_operation(Observability::OP_PING, options.parent_span, self) do |_obs_handler|
330
+ resp = @backend.ping(nil, options.to_backend)
331
+ PingResult.new do |res|
332
+ res.version = resp[:version]
333
+ res.id = resp[:id]
334
+ res.sdk = resp[:sdk]
335
+ resp[:services].each do |type, svcs|
336
+ res.services[type] = svcs.map do |svc|
337
+ PingResult::ServiceInfo.new do |info|
338
+ info.id = svc[:id]
339
+ info.state = svc[:state]
340
+ info.latency = svc[:latency]
341
+ info.remote = svc[:remote]
342
+ info.local = svc[:local]
343
+ info.error = svc[:error]
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ # Waits until the cluster reaches the desired state, actively pinging its services
352
+ #
353
+ # +Thread#raise+ does not interrupt the wait. It ends on success, on +timeout+, or when the cluster is disconnected.
354
+ #
355
+ # @param [Integer, #in_milliseconds] timeout the maximum time to wait
356
+ # @param [Options::WaitUntilReady] options
357
+ #
358
+ # @return [void]
359
+ #
360
+ # @raise [Error::UnambiguousTimeout] if the desired state is not reached within +timeout+
361
+ # @raise [Error::ClusterClosed] if the cluster has been disconnected
362
+ # @raise [Error::InvalidArgument] if +timeout+ is negative or longer than 365 days, or +options+ name an
363
+ # unsupported desired state or service type
364
+ def wait_until_ready(timeout, options = Options::WaitUntilReady::DEFAULT)
365
+ @backend.wait_until_ready(nil, Utils::Time.extract_duration(timeout), options.to_backend)
366
+ end
367
+
368
+ private
369
+
370
+ # Initialize {Cluster} object
371
+ #
372
+ # @overload new(connection_string, options)
373
+ # @param [String] connection_string connection string used to locate the Couchbase Cluster
374
+ # @param [Options::Cluster] options custom options when creating the cluster connection
375
+ #
376
+ # @overload new(connection_string, username, password, options)
377
+ # Shortcut for {PasswordAuthenticator}
378
+ # @param [String] connection_string connection string used to locate the Couchbase Cluster
379
+ # @param [String] username name of the user
380
+ # @param [String] password password of the user
381
+ # @param [Options::Cluster, nil] options custom options when creating the cluster connection
382
+ #
383
+ # @overload new(configuration)
384
+ # @param [Configuration] configuration configuration object
385
+ def initialize(connection_string, *args)
386
+ credentials = {}
387
+ open_options = {}
388
+
389
+ if connection_string.is_a?(Configuration)
390
+ options = connection_string
391
+ connection_string = options.connection_string
392
+ credentials[:username] = options.username
393
+ credentials[:password] = options.password
394
+ raise ArgumentError, "missing connection_string" unless connection_string
395
+ raise ArgumentError, "missing username" unless credentials[:username]
396
+ raise ArgumentError, "missing password" unless credentials[:password]
397
+ else
398
+ options = args.shift
399
+ case options
400
+ when String
401
+ credentials[:username] = options
402
+ credentials[:password] = args.shift
403
+ raise ArgumentError, "missing username" unless credentials[:username]
404
+ raise ArgumentError, "missing password" unless credentials[:password]
405
+ when Options::Cluster
406
+ tracer = options.tracer
407
+ meter = options.meter
408
+ open_options = options.to_backend || {}
409
+ authenticator = options.authenticator
410
+ case authenticator
411
+ when PasswordAuthenticator
412
+ credentials[:username] = authenticator.username
413
+ raise ArgumentError, "missing username" unless credentials[:username]
414
+
415
+ credentials[:password] = authenticator.password
416
+ raise ArgumentError, "missing password" unless credentials[:password]
417
+
418
+ open_options[:allowed_sasl_mechanisms] = authenticator.allowed_sasl_mechanisms
419
+ when CertificateAuthenticator
420
+ credentials[:certificate_path] = authenticator.certificate_path
421
+ raise ArgumentError, "missing certificate path" unless credentials[:certificate_path]
422
+
423
+ credentials[:key_path] = authenticator.key_path
424
+ raise ArgumentError, "missing key path" unless credentials[:key_path]
425
+ when JWTAuthenticator
426
+ credentials[:jwt] = authenticator.token
427
+ raise ArgumentError, "missing token" unless credentials[:jwt]
428
+ else
429
+ raise ArgumentError, "options must have authenticator configured"
430
+ end
431
+ else
432
+ raise ArgumentError, "unexpected second argument, have to be String or Options::Cluster"
433
+ end
434
+ end
435
+
436
+ @backend = Backend.new
437
+
438
+ @observability = Observability::Wrapper.new(backend: @backend) do |w|
439
+ w.tracer = if !open_options[:enable_tracing].nil? && !open_options[:enable_tracing]
440
+ Tracing::NoopTracer.new
441
+ elsif tracer.nil?
442
+ Tracing::ThresholdLoggingTracer.new(
443
+ emit_interval: open_options[:threshold_emit_interval],
444
+ kv_threshold: open_options[:key_value_threshold],
445
+ query_threshold: open_options[:query_threshold],
446
+ views_threshold: open_options[:view_threshold],
447
+ search_threshold: open_options[:search_threshold],
448
+ analytics_threshold: open_options[:analytics_threshold],
449
+ management_threshold: open_options[:management_threshold],
450
+ sample_size: open_options[:threshold_sample_size],
451
+ )
452
+ else
453
+ tracer
454
+ end
455
+ w.meter = if !open_options[:enable_metrics].nil? && !open_options[:enable_metrics]
456
+ Metrics::NoopMeter.new
457
+ elsif meter.nil?
458
+ Metrics::LoggingMeter.new(
459
+ emit_interval: open_options[:metrics_emit_interval],
460
+ )
461
+ else
462
+ meter
463
+ end
464
+ end
465
+
466
+ @backend.open(connection_string, credentials, open_options)
467
+ end
468
+
469
+ # @api private
470
+ def convert_search_result(resp, options)
471
+ SearchResult.new do |res|
472
+ res.meta_data = SearchMetaData.new do |meta|
473
+ meta.metrics.max_score = resp[:meta_data][:metrics][:max_score]
474
+ meta.metrics.error_partition_count = resp[:meta_data][:metrics][:error_partition_count]
475
+ meta.metrics.success_partition_count = resp[:meta_data][:metrics][:success_partition_count]
476
+ meta.metrics.took = resp[:meta_data][:metrics][:took]
477
+ meta.metrics.total_rows = resp[:meta_data][:metrics][:total_rows]
478
+ meta.errors = resp[:meta_data][:errors]
479
+ end
480
+ res.rows = resp[:rows].map do |r|
481
+ SearchRow.new do |row|
482
+ row.transcoder = options.transcoder
483
+ row.index = r[:index]
484
+ row.id = r[:id]
485
+ row.score = r[:score]
486
+ row.fragments = r[:fragments]
487
+ unless r[:locations].empty?
488
+ row.locations = SearchRowLocations.new(
489
+ r[:locations].map do |loc|
490
+ SearchRowLocation.new do |location|
491
+ location.field = loc[:field]
492
+ location.term = loc[:term]
493
+ location.position = loc[:position]
494
+ location.start_offset = loc[:start_offset]
495
+ location.end_offset = loc[:end_offset]
496
+ location.array_positions = loc[:array_positions]
497
+ end
498
+ end,
499
+ )
500
+ end
501
+ row.instance_variable_set(:@fields, r[:fields])
502
+ row.explanation = JSON.parse(r[:explanation]) if r[:explanation]
503
+ end
504
+ end
505
+ if resp[:facets]
506
+ res.facets = resp[:facets].each_with_object({}) do |(k, v), o|
507
+ facet = case options.facets[k]
508
+ when SearchFacet::SearchFacetTerm
509
+ SearchFacetResult::TermFacetResult.new do |f|
510
+ f.terms =
511
+ if v[:terms]
512
+ v[:terms].map do |t|
513
+ SearchFacetResult::TermFacetResult::TermFacet.new(t[:term], t[:count])
514
+ end
515
+ else
516
+ []
517
+ end
518
+ end
519
+ when SearchFacet::SearchFacetDateRange
520
+ SearchFacetResult::DateRangeFacetResult.new do |f|
521
+ f.date_ranges =
522
+ if v[:date_ranges]
523
+ v[:date_ranges].map do |r|
524
+ SearchFacetResult::DateRangeFacetResult::DateRangeFacet.new(r[:name], r[:count], r[:start_time], r[:end_time])
525
+ end
526
+ else
527
+ []
528
+ end
529
+ end
530
+ when SearchFacet::SearchFacetNumericRange
531
+ SearchFacetResult::NumericRangeFacetResult.new do |f|
532
+ f.numeric_ranges =
533
+ if v[:numeric_ranges]
534
+ v[:numeric_ranges].map do |r|
535
+ SearchFacetResult::NumericRangeFacetResult::NumericRangeFacet.new(r[:name], r[:count], r[:min], r[:max])
536
+ end
537
+ else
538
+ []
539
+ end
540
+ end
541
+ else
542
+ next # ignore unknown facet result
543
+ end
544
+ facet.name = v[:name]
545
+ facet.field = v[:field]
546
+ facet.total = v[:total]
547
+ facet.missing = v[:missing]
548
+ facet.other = v[:other]
549
+ o[k] = facet
550
+ end
551
+ end
552
+ end
553
+ end
554
+ end
555
+ 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