couchbase 3.0.0.alpha.3-universal-darwin-19 → 3.0.0.alpha.4-universal-darwin-19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/tests-6.0.3.yml +4 -1
  3. data/.github/workflows/tests-dev-preview.yml +4 -1
  4. data/.github/workflows/tests.yml +4 -1
  5. data/README.md +1 -1
  6. data/bin/check-cluster +31 -0
  7. data/bin/init-cluster +16 -4
  8. data/examples/analytics.rb +221 -0
  9. data/examples/managing_analytics_indexes.rb +72 -0
  10. data/examples/managing_view_indexes.rb +54 -0
  11. data/examples/search_with_consistency.rb +84 -0
  12. data/examples/view.rb +50 -0
  13. data/ext/.clang-tidy +1 -0
  14. data/ext/build_version.hxx.in +1 -1
  15. data/ext/couchbase/bucket.hxx +0 -1
  16. data/ext/couchbase/couchbase.cxx +1421 -55
  17. data/ext/couchbase/io/dns_client.hxx +215 -0
  18. data/ext/couchbase/io/dns_codec.hxx +207 -0
  19. data/ext/couchbase/io/dns_config.hxx +116 -0
  20. data/ext/couchbase/io/dns_message.hxx +558 -0
  21. data/ext/couchbase/io/http_session.hxx +16 -4
  22. data/ext/couchbase/io/mcbp_session.hxx +2 -1
  23. data/ext/couchbase/mutation_token.hxx +1 -1
  24. data/ext/couchbase/operations.hxx +19 -0
  25. data/ext/couchbase/operations/analytics_dataset_create.hxx +117 -0
  26. data/ext/couchbase/operations/analytics_dataset_drop.hxx +103 -0
  27. data/ext/couchbase/operations/analytics_dataset_get_all.hxx +107 -0
  28. data/ext/couchbase/operations/analytics_dataverse_create.hxx +104 -0
  29. data/ext/couchbase/operations/analytics_dataverse_drop.hxx +104 -0
  30. data/ext/couchbase/operations/analytics_get_pending_mutations.hxx +91 -0
  31. data/ext/couchbase/operations/analytics_index_create.hxx +128 -0
  32. data/ext/couchbase/operations/analytics_index_drop.hxx +110 -0
  33. data/ext/couchbase/operations/analytics_index_get_all.hxx +106 -0
  34. data/ext/couchbase/operations/analytics_link_connect.hxx +102 -0
  35. data/ext/couchbase/operations/analytics_link_disconnect.hxx +101 -0
  36. data/ext/couchbase/operations/design_document.hxx +59 -0
  37. data/ext/couchbase/operations/document_analytics.hxx +293 -0
  38. data/ext/couchbase/operations/document_query.hxx +2 -2
  39. data/ext/couchbase/operations/document_search.hxx +19 -1
  40. data/ext/couchbase/operations/document_view.hxx +227 -0
  41. data/ext/couchbase/operations/search_index.hxx +17 -0
  42. data/ext/couchbase/operations/search_index_control_ingest.hxx +3 -1
  43. data/ext/couchbase/operations/view_index_drop.hxx +67 -0
  44. data/ext/couchbase/operations/view_index_get.hxx +90 -0
  45. data/ext/couchbase/operations/view_index_get_all.hxx +125 -0
  46. data/ext/couchbase/operations/view_index_upsert.hxx +87 -0
  47. data/ext/couchbase/service_type.hxx +38 -1
  48. data/ext/couchbase/timeout_defaults.hxx +3 -1
  49. data/ext/couchbase/utils/connection_string.hxx +231 -0
  50. data/ext/couchbase/version.hxx +1 -1
  51. data/ext/test/main.cxx +3 -12
  52. data/lib/couchbase/analytics_options.rb +165 -0
  53. data/lib/couchbase/bucket.rb +49 -0
  54. data/lib/couchbase/cluster.rb +46 -207
  55. data/lib/couchbase/management/analytics_index_manager.rb +138 -24
  56. data/lib/couchbase/management/view_index_manager.rb +63 -10
  57. data/lib/couchbase/query_options.rb +219 -0
  58. data/lib/couchbase/search_options.rb +6 -6
  59. data/lib/couchbase/version.rb +1 -1
  60. data/lib/couchbase/view_options.rb +155 -0
  61. metadata +34 -2
@@ -18,7 +18,7 @@
18
18
  #pragma once
19
19
 
20
20
  #define BACKEND_VERSION_MAJOR 0
21
- #define BACKEND_VERSION_MINOR 3
21
+ #define BACKEND_VERSION_MINOR 4
22
22
  #define BACKEND_VERSION_PATCH 0
23
23
 
24
24
  #include <build_version.hxx>
data/ext/test/main.cxx CHANGED
@@ -44,23 +44,14 @@ main()
44
44
  rb_require("json");
45
45
  run_script(R"(
46
46
  p Couchbase::VERSION
47
- )");
48
-
49
- run_script(R"(
50
47
  B = Couchbase::Backend.new
51
48
  B.open("localhost", "Administrator", "password")
52
- )");
53
49
 
54
- run_script(R"(
55
- query = {
56
- query: "hello"
57
- }
58
- p B.document_search("beers", JSON.generate(query), {})
50
+ pp B.document_view("beer-sample", "test", "get_all", :development, {
51
+ keys: [JSON.generate("21st_amendment_brewery_cafe-563_stout")]
52
+ })
59
53
  )");
60
54
 
61
- run_script(R"(
62
- B.close
63
- )");
64
55
 
65
56
  ruby_finalize();
66
57
  return 0;
@@ -0,0 +1,165 @@
1
+ # Copyright 2020 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/json_transcoder'
16
+
17
+ module Couchbase
18
+ class Cluster
19
+ class AnalyticsOptions
20
+ # @return [Integer] Timeout in milliseconds
21
+ attr_accessor :timeout
22
+
23
+ # @return [String] Provides a custom client context ID for this query
24
+ attr_accessor :client_context_id
25
+
26
+ # @return [:not_bounded, :request_plus] specifies level of consistency for the query
27
+ attr_accessor :scan_consistency
28
+
29
+ # @return [Integer] The maximum duration (in milliseconds) the query engine is willing to wait before failing.
30
+ attr_accessor :scan_wait
31
+
32
+ # @return [Boolean] Allows explicitly marking a query as being readonly and not mutating and documents on the server side.
33
+ attr_accessor :readonly
34
+
35
+ # @return [Boolean] Allows to give certain requests higher priority than others
36
+ attr_accessor :priority
37
+
38
+ # @return [JsonTranscoder] transcoder to use on rows
39
+ attr_accessor :transcoder
40
+
41
+ # @yieldparam [AnalyticsOptions] self
42
+ def initialize
43
+ @transcoder = JsonTranscoder.new
44
+ @raw_parameters = {}
45
+ @positional_parameters = nil
46
+ @named_parameters = nil
47
+ @scan_consistency = nil
48
+ yield self if block_given?
49
+ end
50
+
51
+ # Sets positional parameters for the query
52
+ #
53
+ # @param [Array] positional the list of parameters that have to be substituted in the statement
54
+ def positional_parameters(positional)
55
+ @positional_parameters = positional
56
+ @named_parameters = nil
57
+ end
58
+
59
+ # Sets named parameters for the query
60
+ #
61
+ # @param [Hash] named the key/value map of the parameters to substitute in the statement
62
+ def named_parameters(named)
63
+ @named_parameters = named
64
+ @positional_parameters = nil
65
+ end
66
+
67
+ # Allows providing custom JSON key/value pairs for advanced usage
68
+ #
69
+ # @param [String] key the parameter name (key of the JSON property)
70
+ # @param [Object] value the parameter value (value of the JSON property)
71
+ def raw(key, value)
72
+ @raw_parameters[key] = JSON.generate(value)
73
+ end
74
+ end
75
+
76
+ class AnalyticsWarning
77
+ # @return [Integer]
78
+ attr_accessor :code
79
+
80
+ # @return [String]
81
+ attr_accessor :message
82
+
83
+ # @param [Integer] code
84
+ # @param [String] message
85
+ def initialize(code, message)
86
+ @code = code
87
+ @message = message
88
+ end
89
+ end
90
+
91
+ class AnalyticsMetrics
92
+ # @return [Integer] duration in milliseconds
93
+ attr_accessor :elapsed_time
94
+
95
+ # @return [Integer] duration in milliseconds
96
+ attr_accessor :execution_time
97
+
98
+ # @return [Integer]
99
+ attr_accessor :result_count
100
+
101
+ # @return [Integer]
102
+ attr_accessor :result_size
103
+
104
+ # @return [Integer]
105
+ attr_accessor :error_count
106
+
107
+ # @return [Integer]
108
+ attr_accessor :processed_objects
109
+
110
+ # @return [Integer]
111
+ attr_accessor :warning_count
112
+
113
+ # @yieldparam [AnalyticsMetrics] self
114
+ def initialize
115
+ yield self if block_given?
116
+ end
117
+ end
118
+
119
+ class AnalyticsMetaData
120
+ # @return [String]
121
+ attr_accessor :request_id
122
+
123
+ # @return [String]
124
+ attr_accessor :client_context_id
125
+
126
+ # @return [:running, :success, :errors, :completed, :stopped, :timeout, :closed, :fatal, :aborted, :unknown]
127
+ attr_accessor :status
128
+
129
+ # @return [Hash] returns the signature as returned by the query engine which is then decoded as JSON object
130
+ attr_accessor :signature
131
+
132
+ # @return [Array<AnalyticsWarning>]
133
+ attr_accessor :warnings
134
+
135
+ # @return [AnalyticsMetrics]
136
+ attr_accessor :metrics
137
+
138
+ # @yieldparam [AnalyticsMetaData] self
139
+ def initialize
140
+ yield self if block_given?
141
+ end
142
+ end
143
+
144
+ class AnalyticsResult
145
+ # @return [AnalyticsMetaData]
146
+ attr_accessor :meta_data
147
+
148
+ attr_accessor :transcoder
149
+
150
+ # Returns all rows converted using a transcoder
151
+ #
152
+ # @return [Array]
153
+ def rows(transcoder = self.transcoder)
154
+ @rows.lazy.map { |row| transcoder.decode(row, 0) }
155
+ end
156
+
157
+ # @yieldparam [AnalyticsResult] self
158
+ def initialize
159
+ @transcoder = JsonTranscoder.new
160
+ yield self if block_given?
161
+ end
162
+ end
163
+ end
164
+ end
165
+
@@ -14,6 +14,8 @@
14
14
 
15
15
  require "couchbase/scope"
16
16
  require "couchbase/management/collection_manager"
17
+ require "couchbase/management/view_index_manager"
18
+ require "couchbase/view_options"
17
19
 
18
20
  module Couchbase
19
21
  class Bucket
@@ -58,11 +60,58 @@ module Couchbase
58
60
  default_scope.default_collection
59
61
  end
60
62
 
63
+ # Performs query to view index.
64
+ #
65
+ # @param [String] design_document_name name of the design document
66
+ # @param [String] view_name name of the view to query
67
+ # @param [ViewOptions] options
68
+ #
69
+ # @return [ViewQueryResult]
70
+ def view_query(design_document_name, view_name, options = ViewOptions.new)
71
+ resp = @backend.document_view(@name, design_document_name, view_name, options.namespace, {
72
+ timeout: options.timeout,
73
+ scan_consistency: options.scan_consistency,
74
+ skip: options.skip,
75
+ limit: options.limit,
76
+ start_key: (JSON.generate(options.start_key) unless options.start_key.nil?),
77
+ end_key: (JSON.generate(options.end_key) unless options.end_key.nil?),
78
+ start_key_doc_id: options.start_key_doc_id,
79
+ end_key_doc_id: options.end_key_doc_id,
80
+ inclusive_end: options.inclusive_end,
81
+ group: options.group,
82
+ group_level: options.group_level,
83
+ key: (JSON.generate(options.key) unless options.key.nil?),
84
+ keys: options.keys&.map { |key| JSON.generate(key) },
85
+ order: options.order,
86
+ reduce: options.reduce,
87
+ on_error: options.on_error,
88
+ debug: options.debug,
89
+ })
90
+ ViewResult.new do |res|
91
+ res.meta_data = ViewMetaData.new do |meta|
92
+ meta.total_rows = resp[:meta][:total_rows]
93
+ meta.debug_info = resp[:meta][:debug_info]
94
+ end
95
+ res.rows = resp[:rows].map do |entry|
96
+ ViewRow.new do |row|
97
+ row.id = entry[:id] if entry.key?(:id)
98
+ row.key = JSON.parse(entry[:key])
99
+ row.value = JSON.parse(entry[:value])
100
+ end
101
+ end
102
+ end
103
+ end
104
+
61
105
  # @return [Management::CollectionManager]
62
106
  def collections
63
107
  Management::CollectionManager.new(@backend, @name)
64
108
  end
65
109
 
110
+ # @return [Management::ViewIndexManager]
111
+ def view_indexes
112
+ Management::ViewIndexManager.new(@backend, @name)
113
+ end
114
+
66
115
  # Performs application-level ping requests against services in the couchbase cluster
67
116
  #
68
117
  # @return [PingResult]
@@ -22,6 +22,8 @@ require "couchbase/management/analytics_index_manager"
22
22
  require "couchbase/management/search_index_manager"
23
23
 
24
24
  require "couchbase/search_options"
25
+ require "couchbase/query_options"
26
+ require "couchbase/analytics_options"
25
27
 
26
28
  module Couchbase
27
29
  class Cluster
@@ -87,6 +89,7 @@ module Couchbase
87
89
  metrics.execution_time = resp[:meta][:metrics][:execution_time]
88
90
  metrics.sort_count = resp[:meta][:metrics][:sort_count]
89
91
  metrics.result_count = resp[:meta][:metrics][:result_count]
92
+ metrics.result_size = resp[:meta][:metrics][:result_size]
90
93
  metrics.mutation_count = resp[:meta][:metrics][:mutation_count]
91
94
  metrics.error_count = resp[:meta][:metrics][:error_count]
92
95
  metrics.warning_count = resp[:meta][:metrics][:warning_count]
@@ -104,7 +107,42 @@ module Couchbase
104
107
  # @param [AnalyticsOptions] options the custom options for this query
105
108
  #
106
109
  # @return [AnalyticsResult]
107
- def analytics_query(statement, options = AnalyticsOptions.new) end
110
+ def analytics_query(statement, options = AnalyticsOptions.new)
111
+ resp = @backend.document_analytics(statement, {
112
+ timeout: options.timeout,
113
+ client_context_id: options.client_context_id,
114
+ scan_consistency: options.scan_consistency,
115
+ readonly: options.readonly,
116
+ priority: options.priority,
117
+ positional_parameters: options.instance_variable_get("@positional_parameters")&.map { |p| JSON.dump(p) },
118
+ named_parameters: options.instance_variable_get("@named_parameters")&.each_with_object({}) { |(n, v), o| o[n.to_s] = JSON.dump(v) },
119
+ raw_parameters: options.instance_variable_get("@raw_parameters"),
120
+ })
121
+
122
+ AnalyticsResult.new do |res|
123
+ res.transcoder = options.transcoder
124
+ res.meta_data = AnalyticsMetaData.new do |meta|
125
+ meta.status = resp[:meta][:status]
126
+ meta.request_id = resp[:meta][:request_id]
127
+ meta.client_context_id = resp[:meta][:client_context_id]
128
+ meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
129
+ meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
130
+ meta.metrics = AnalyticsMetrics.new do |metrics|
131
+ if resp[:meta][:metrics]
132
+ metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
133
+ metrics.execution_time = resp[:meta][:metrics][:execution_time]
134
+ metrics.result_count = resp[:meta][:metrics][:result_count]
135
+ metrics.result_size = resp[:meta][:metrics][:result_size]
136
+ metrics.error_count = resp[:meta][:metrics][:error_count]
137
+ metrics.warning_count = resp[:meta][:metrics][:warning_count]
138
+ metrics.processed_objects = resp[:meta][:metrics][:processed_objects]
139
+ end
140
+ end
141
+ res[:warnings] = resp[:warnings].map { |warn| QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
142
+ end
143
+ res.instance_variable_set("@rows", resp[:rows])
144
+ end
145
+ end
108
146
 
109
147
  # Performs a Full Text Search (FTS) query
110
148
  #
@@ -243,210 +281,6 @@ module Couchbase
243
281
  end
244
282
  end
245
283
 
246
- class QueryOptions
247
- # @return [Integer] Timeout in milliseconds
248
- attr_accessor :timeout
249
-
250
- # @return [Boolean] Allows turning this request into a prepared statement query
251
- attr_accessor :adhoc
252
-
253
- # @return [String] Provides a custom client context ID for this query
254
- attr_accessor :client_context_id
255
-
256
- # @return [Integer] Allows overriding the default maximum parallelism for the query execution on the server side.
257
- attr_accessor :max_parallelism
258
-
259
- # @return [Boolean] Allows explicitly marking a query as being readonly and not mutating and documents on the server side.
260
- attr_accessor :readonly
261
-
262
- # Allows customizing how long (in milliseconds) the query engine is willing to wait until the index catches up to whatever scan consistency is asked for in this query.
263
- #
264
- # @note that if +:not_bounded+ consistency level is used, this method doesn't do anything
265
- # at all. If no value is provided to this method, the server default is used.
266
- #
267
- # @return [Integer] The maximum duration (in milliseconds) the query engine is willing to wait before failing.
268
- attr_accessor :scan_wait
269
-
270
- # @return [Integer] Supports customizing the maximum buffered channel size between the indexer and the query service
271
- attr_accessor :scan_cap
272
-
273
- # @return [Integer] Supports customizing the number of items execution operators can batch for fetch from the KV layer on the server.
274
- attr_accessor :pipeline_batch
275
-
276
- # @return [Integer] Allows customizing the maximum number of items each execution operator can buffer between various operators on the server.
277
- attr_accessor :pipeline_cap
278
-
279
- # @return [Boolean] Enables per-request metrics in the trailing section of the query
280
- attr_accessor :metrics
281
-
282
- # @return [:off, :phases, :timings] Customize server profile level for this query
283
- attr_accessor :profile
284
-
285
- def initialize
286
- @timeout = 75_000 # ms
287
- @adhoc = true
288
- @raw_parameters = {}
289
- @positional_parameters = nil
290
- @named_parameters = nil
291
- @scan_consistency = nil
292
- @mutation_state = nil
293
- yield self if block_given?
294
- end
295
-
296
- # Allows providing custom JSON key/value pairs for advanced usage
297
- #
298
- # @param [String] key the parameter name (key of the JSON property)
299
- # @param [Object] value the parameter value (value of the JSON property)
300
- def raw(key, value)
301
- @raw_parameters[key] = JSON.generate(value)
302
- end
303
-
304
- # Customizes the consistency guarantees for this query
305
- #
306
- # @note overrides consistency level set by {#consistent_with}
307
- #
308
- # [+:not_bounded+] The indexer will return whatever state it has to the query engine at the time of query. This is the default (for single-statement requests).
309
- #
310
- # [+:request_plus+] The indexer will wait until all mutations have been processed at the time of request before returning to the query engine.
311
- #
312
- # @param [:not_bounded, :request_plus] level the index scan consistency to be used for this query
313
- def scan_consistency=(level)
314
- @mutation_state = nil if @mutation_state
315
- @scan_consistency = level
316
- end
317
-
318
- # Sets the mutation tokens this query should be consistent with
319
- #
320
- # @note overrides consistency level set by {#scan_consistency=}
321
- #
322
- # @param [MutationState] mutation_state the mutation state containing the mutation tokens
323
- def consistent_with(mutation_state)
324
- @scan_consistency = nil if @scan_consistency
325
- @mutation_state = mutation_state
326
- end
327
-
328
- # Sets positional parameters for the query
329
- #
330
- # @param [Array] positional the list of parameters that have to be substituted in the statement
331
- def positional_parameters(positional)
332
- @positional_parameters = positional
333
- @named_parameters = nil
334
- end
335
-
336
- # Sets named parameters for the query
337
- #
338
- # @param [Hash] named the key/value map of the parameters to substitute in the statement
339
- def named_parameters(named)
340
- @named_parameters = named
341
- @positional_parameters = nil
342
- end
343
- end
344
-
345
- class QueryResult
346
- # @return [QueryMetaData] returns object representing additional metadata associated with this query
347
- attr_accessor :meta_data
348
-
349
- attr_accessor :transcoder
350
-
351
- # Returns all rows converted using a transcoder
352
- #
353
- # @return [Array]
354
- def rows(transcoder = self.transcoder)
355
- @rows.lazy.map do |row|
356
- if transcoder == :json
357
- JSON.parse(row)
358
- else
359
- transcoder.call(row)
360
- end
361
- end
362
- end
363
-
364
- # @yieldparam [QueryResult] self
365
- def initialize
366
- yield self if block_given?
367
- @transcoder = :json
368
- end
369
- end
370
-
371
- class QueryMetaData
372
- # @return [String] returns the request identifier string of the query request
373
- attr_accessor :request_id
374
-
375
- # @return [String] returns the client context identifier string set of the query request
376
- attr_accessor :client_context_id
377
-
378
- # @return [Symbol] returns raw query execution status as returned by the query engine
379
- attr_accessor :status
380
-
381
- # @return [Hash] returns the signature as returned by the query engine which is then decoded as JSON object
382
- attr_accessor :signature
383
-
384
- # @return [Hash] returns the profiling information returned by the query engine which is then decoded as JSON object
385
- attr_accessor :profile
386
-
387
- # @return [QueryMetrics] metrics as returned by the query engine, if enabled
388
- attr_accessor :metrics
389
-
390
- # @return [List<QueryWarning>] list of warnings returned by the query engine
391
- attr_accessor :warnings
392
-
393
- # @yieldparam [QueryMetaData] self
394
- def initialize
395
- yield self if block_given?
396
- end
397
- end
398
-
399
- class QueryMetrics
400
- # @return [Integer] The total time taken for the request, that is the time from when the request was received until the results were returned
401
- attr_accessor :elapsed_time
402
-
403
- # @return [Integer] The time taken for the execution of the request, that is the time from when query execution started until the results were returned
404
- attr_accessor :execution_time
405
-
406
- # @return [Integer] the total number of results selected by the engine before restriction through LIMIT clause.
407
- attr_accessor :sort_count
408
-
409
- # @return [Integer] The total number of objects in the results.
410
- attr_accessor :result_count
411
-
412
- # @return [Integer] The total number of bytes in the results.
413
- attr_accessor :result_size
414
-
415
- # @return [Integer] The number of mutations that were made during the request.
416
- attr_accessor :mutation_count
417
-
418
- # @return [Integer] The number of errors that occurred during the request.
419
- attr_accessor :error_count
420
-
421
- # @return [Integer] The number of warnings that occurred during the request.
422
- attr_accessor :warning_count
423
-
424
- # @yieldparam [QueryMetrics] self
425
- def initialize
426
- yield self if block_given?
427
- end
428
- end
429
-
430
- # Represents a single warning returned from the query engine.
431
- class QueryWarning
432
- # @return [Integer]
433
- attr_accessor :code
434
-
435
- # @return [String]
436
- attr_accessor :message
437
-
438
- def initialize(code, message)
439
- @code = code
440
- @message = message
441
- end
442
- end
443
-
444
- class AnalyticsOptions
445
- def initialize
446
- yield self if block_given?
447
- end
448
- end
449
-
450
284
  class DiagnosticsOptions
451
285
  # @return [String] Holds custom report id.
452
286
  attr_accessor :report_id
@@ -458,9 +292,14 @@ module Couchbase
458
292
 
459
293
  private
460
294
 
295
+ # Initialize {Cluster} object
296
+ #
297
+ # @param [String] connection_string connection string used to locate the Couchbase Cluster
298
+ # @param [ClusterOptions] options custom options when creating the cluster connection
461
299
  def initialize(connection_string, options)
462
- hostname = connection_string[%r{^couchbase://(.*)}, 1]
463
- raise ArgumentError, "missing hostname" unless hostname
300
+ conn_info = Backend.parse_connection_string(connection_string)
301
+ raise ArgumentError, "missing hostname" if conn_info[:nodes].empty?
302
+ hostname = conn_info[:nodes].first[:address]
464
303
  raise ArgumentError, "options must have authenticator configured" unless options.authenticator
465
304
  username = options.authenticator.username
466
305
  raise ArgumentError, "missing username" unless username