couchbase 3.5.2-x86_64-darwin

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