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.
Files changed (126) 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 +339 -0
  6. data/lib/couchbase/3.0/libcouchbase.bundle +0 -0
  7. data/lib/couchbase/3.1/libcouchbase.bundle +0 -0
  8. data/lib/couchbase/3.2/libcouchbase.bundle +0 -0
  9. data/lib/couchbase/3.3/libcouchbase.bundle +0 -0
  10. data/lib/couchbase/analytics_options.rb +107 -0
  11. data/lib/couchbase/authenticator.rb +64 -0
  12. data/lib/couchbase/binary_collection.rb +128 -0
  13. data/lib/couchbase/binary_collection_options.rb +24 -0
  14. data/lib/couchbase/bucket.rb +144 -0
  15. data/lib/couchbase/cluster.rb +460 -0
  16. data/lib/couchbase/cluster_registry.rb +49 -0
  17. data/lib/couchbase/collection.rb +705 -0
  18. data/lib/couchbase/collection_options.rb +399 -0
  19. data/lib/couchbase/config_profiles.rb +55 -0
  20. data/lib/couchbase/configuration.rb +56 -0
  21. data/lib/couchbase/datastructures/couchbase_list.rb +160 -0
  22. data/lib/couchbase/datastructures/couchbase_map.rb +194 -0
  23. data/lib/couchbase/datastructures/couchbase_queue.rb +134 -0
  24. data/lib/couchbase/datastructures/couchbase_set.rb +128 -0
  25. data/lib/couchbase/datastructures.rb +24 -0
  26. data/lib/couchbase/diagnostics.rb +181 -0
  27. data/lib/couchbase/errors.rb +376 -0
  28. data/lib/couchbase/json_transcoder.rb +39 -0
  29. data/lib/couchbase/key_value_scan.rb +117 -0
  30. data/lib/couchbase/libcouchbase.rb +6 -0
  31. data/lib/couchbase/logger.rb +85 -0
  32. data/lib/couchbase/management/analytics_index_manager.rb +1127 -0
  33. data/lib/couchbase/management/bucket_manager.rb +443 -0
  34. data/lib/couchbase/management/collection_manager.rb +470 -0
  35. data/lib/couchbase/management/collection_query_index_manager.rb +222 -0
  36. data/lib/couchbase/management/query_index_manager.rb +617 -0
  37. data/lib/couchbase/management/scope_search_index_manager.rb +198 -0
  38. data/lib/couchbase/management/search_index_manager.rb +424 -0
  39. data/lib/couchbase/management/user_manager.rb +468 -0
  40. data/lib/couchbase/management/view_index_manager.rb +237 -0
  41. data/lib/couchbase/management.rb +29 -0
  42. data/lib/couchbase/mutation_state.rb +63 -0
  43. data/lib/couchbase/options.rb +2837 -0
  44. data/lib/couchbase/protostellar/binary_collection.rb +55 -0
  45. data/lib/couchbase/protostellar/bucket.rb +51 -0
  46. data/lib/couchbase/protostellar/client.rb +99 -0
  47. data/lib/couchbase/protostellar/cluster.rb +163 -0
  48. data/lib/couchbase/protostellar/collection.rb +152 -0
  49. data/lib/couchbase/protostellar/connect_options.rb +63 -0
  50. data/lib/couchbase/protostellar/error_handling.rb +203 -0
  51. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +61 -0
  52. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +35 -0
  53. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +57 -0
  54. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +36 -0
  55. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +61 -0
  56. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +37 -0
  57. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +72 -0
  58. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +44 -0
  59. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +52 -0
  60. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +30 -0
  61. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +70 -0
  62. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +36 -0
  63. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +97 -0
  64. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +46 -0
  65. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +57 -0
  66. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +30 -0
  67. data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +52 -0
  68. data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +30 -0
  69. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +99 -0
  70. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +30 -0
  71. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +57 -0
  72. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +36 -0
  73. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +51 -0
  74. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +30 -0
  75. data/lib/couchbase/protostellar/generated.rb +9 -0
  76. data/lib/couchbase/protostellar/management/bucket_manager.rb +67 -0
  77. data/lib/couchbase/protostellar/management/collection_manager.rb +94 -0
  78. data/lib/couchbase/protostellar/management/collection_query_index_manager.rb +124 -0
  79. data/lib/couchbase/protostellar/management/query_index_manager.rb +112 -0
  80. data/lib/couchbase/protostellar/management.rb +24 -0
  81. data/lib/couchbase/protostellar/request.rb +78 -0
  82. data/lib/couchbase/protostellar/request_behaviour.rb +42 -0
  83. data/lib/couchbase/protostellar/request_generator/admin/bucket.rb +124 -0
  84. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +94 -0
  85. data/lib/couchbase/protostellar/request_generator/admin/query.rb +130 -0
  86. data/lib/couchbase/protostellar/request_generator/admin.rb +24 -0
  87. data/lib/couchbase/protostellar/request_generator/kv.rb +474 -0
  88. data/lib/couchbase/protostellar/request_generator/query.rb +133 -0
  89. data/lib/couchbase/protostellar/request_generator/search.rb +387 -0
  90. data/lib/couchbase/protostellar/request_generator.rb +26 -0
  91. data/lib/couchbase/protostellar/response_converter/admin/bucket.rb +55 -0
  92. data/lib/couchbase/protostellar/response_converter/admin/collection.rb +42 -0
  93. data/lib/couchbase/protostellar/response_converter/admin/query.rb +59 -0
  94. data/lib/couchbase/protostellar/response_converter/admin.rb +24 -0
  95. data/lib/couchbase/protostellar/response_converter/kv.rb +151 -0
  96. data/lib/couchbase/protostellar/response_converter/query.rb +84 -0
  97. data/lib/couchbase/protostellar/response_converter/search.rb +136 -0
  98. data/lib/couchbase/protostellar/response_converter.rb +26 -0
  99. data/lib/couchbase/protostellar/retry/action.rb +38 -0
  100. data/lib/couchbase/protostellar/retry/orchestrator.rb +60 -0
  101. data/lib/couchbase/protostellar/retry/reason.rb +67 -0
  102. data/lib/couchbase/protostellar/retry/strategies/best_effort.rb +49 -0
  103. data/lib/couchbase/protostellar/retry/strategies.rb +26 -0
  104. data/lib/couchbase/protostellar/retry.rb +28 -0
  105. data/lib/couchbase/protostellar/scope.rb +57 -0
  106. data/lib/couchbase/protostellar/timeout_defaults.rb +30 -0
  107. data/lib/couchbase/protostellar/timeouts.rb +83 -0
  108. data/lib/couchbase/protostellar.rb +29 -0
  109. data/lib/couchbase/query_options.rb +120 -0
  110. data/lib/couchbase/railtie.rb +45 -0
  111. data/lib/couchbase/raw_binary_transcoder.rb +37 -0
  112. data/lib/couchbase/raw_json_transcoder.rb +38 -0
  113. data/lib/couchbase/raw_string_transcoder.rb +40 -0
  114. data/lib/couchbase/scope.rb +256 -0
  115. data/lib/couchbase/search_options.rb +1622 -0
  116. data/lib/couchbase/subdoc.rb +290 -0
  117. data/lib/couchbase/transcoder_flags.rb +62 -0
  118. data/lib/couchbase/utils/generic_logger_adapter.rb +38 -0
  119. data/lib/couchbase/utils/stdlib_logger_adapter.rb +65 -0
  120. data/lib/couchbase/utils/time.rb +69 -0
  121. data/lib/couchbase/utils.rb +21 -0
  122. data/lib/couchbase/version.rb +23 -0
  123. data/lib/couchbase/view_options.rb +65 -0
  124. data/lib/couchbase.rb +28 -0
  125. data/lib/rails/generators/couchbase/config/config_generator.rb +27 -0
  126. 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