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,342 @@
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"
18
+ require "digest/sha2"
19
+ require "active_support/cache"
20
+
21
+ module ActiveSupport
22
+ module Cache
23
+ # A cache store implementation which stores data in Couchbase: https://couchbase.com
24
+ #
25
+ # * Local cache. Hot in-memory primary cache within block/middleware scope.
26
+ # * +read_multi+ and +write_multi+ support.
27
+ # * +delete_matched+ support using N1QL queries.
28
+ # * +clear+ for erasing whole collection (optionally can flush the bucket).
29
+ #
30
+ # To use this store, add the select it in application config
31
+ #
32
+ # config.cache_store = :couchbase_store, {
33
+ # connection_string: "couchbase://localhost",
34
+ # username: "app_cache_user",
35
+ # password: "s3cret",
36
+ # bucket: "app_cache"
37
+ # }
38
+ #
39
+ # @see https://guides.rubyonrails.org/caching_with_rails.html#cache-stores
40
+ class CouchbaseStore < Store
41
+ MAX_KEY_BYTESIZE = 250
42
+ DEFAULT_ERROR_HANDLER = lambda do |method:, returning:, exception:, logger: CouchbaseStore.logger|
43
+ logger&.error { "CouchbaseStore: #{method} failed, returned #{returning.inspect}: #{exception.class}: #{exception.message}" }
44
+ end
45
+
46
+ # Advertise cache versioning support.
47
+ def self.supports_cache_versioning?
48
+ true
49
+ end
50
+
51
+ prepend Strategy::LocalCache
52
+
53
+ def initialize(options = nil)
54
+ super
55
+ @error_handler = @options.delete(:error_handler) { DEFAULT_ERROR_HANDLER }
56
+ @couchbase_options = {}
57
+ @couchbase_options[:connection_string] =
58
+ @options.delete(:connection_string) do
59
+ raise ArgumentError, "Missing connection string for Couchbase cache store. Use :connection_string in the store options"
60
+ end
61
+ @couchbase_options[:username] =
62
+ @options.delete(:username) do
63
+ raise ArgumentError, "Missing username for Couchbase cache store. Use :username in the store options"
64
+ end
65
+ @couchbase_options[:password] =
66
+ @options.delete(:password) do
67
+ raise ArgumentError, "Missing password for Couchbase cache store. Use :password in the store options"
68
+ end
69
+ @couchbase_options[:bucket] =
70
+ @options.delete(:bucket) { raise ArgumentError, "Missing bucket for Couchbase cache store. Use :bucket in the store options" }
71
+ @couchbase_options[:scope] = @options.delete(:scope) if @options.key?(:scope)
72
+ @couchbase_options[:collection] = @options.delete(:collection) if @options.key?(:collection)
73
+ @last_mutation_token = nil
74
+ end
75
+
76
+ def collection
77
+ @collection ||= build_collection
78
+ end
79
+
80
+ def cluster
81
+ @cluster ||= build_cluster
82
+ end
83
+
84
+ def inspect
85
+ "#<#{self.class} options=#{options.inspect} collection=#{@collection.inspect}>"
86
+ end
87
+
88
+ # Deletes all entries with keys matching the regular expression.
89
+ #
90
+ # The +matcher+ must be valid pattern for N1QL +REGEXP_MATCHES+ function. More info at
91
+ # https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/patternmatchingfun.html#section_regex_matches
92
+ #
93
+ # Because the operation performed on query engine, and it might take time to propagate changes
94
+ # from key/value engine to the indexer. Therefore the keys, that were created a moment ago
95
+ # might not be deleted.
96
+ #
97
+ # Also this method assumes, that primary index created on the target bucket
98
+ def delete_matched(matcher, _options = nil)
99
+ pattern =
100
+ case matcher
101
+ when Regexp
102
+ matcher.inspect[1..-2]
103
+ when String
104
+ matcher.tr("?", ".").gsub("*", ".*")
105
+ else
106
+ raise NotImplementedError, "Unable to convert #{matcher.inspect} to Regexp pattern"
107
+ end
108
+ operation_options = ::Couchbase::Options::Query(named_parameters: {"pattern" => pattern}, metrics: true)
109
+ operation_options.consistent_with(::Couchbase::MutationState.new(@last_mutation_token)) if @last_mutation_token
110
+ begin
111
+ result = cluster.query("DELETE FROM #{scope_qualifier} cache_store_ WHERE REGEXP_MATCHES(META(cache_store_).id, $pattern)",
112
+ operation_options)
113
+ result.meta_data.metrics.mutation_count
114
+ rescue ::Couchbase::Error::ParsingFailure, ::Couchbase::Error::ServiceNotAvailable
115
+ raise NotImplementedError, "The server does not support delete_matched operation"
116
+ end
117
+ end
118
+
119
+ # Increments an integer value in the cache.
120
+ #
121
+ # Note that it uses binary collection interface, therefore will fail if the value is not
122
+ # represented as ASCII-encoded number using +:raw+.
123
+ def increment(name, amount = 1, expires_in: nil, initial: nil, **options)
124
+ instrument :increment, name, amount: amount do
125
+ failsafe :increment do
126
+ key = normalize_key(name, options)
127
+ res = collection.binary.increment(
128
+ key, ::Couchbase::Options::Increment(delta: amount, expiry: expires_in, initial: initial)
129
+ )
130
+ @last_mutation_token = res.mutation_token
131
+ res.content
132
+ end
133
+ end
134
+ end
135
+
136
+ # Decrements an integer value in the cache.
137
+ #
138
+ # Note that it uses binary collection interface, therefore will fail if the value is not
139
+ # represented as ASCII-encoded number using +:raw+.
140
+ #
141
+ # Note that the counter represented by non-negative number on the server, and it will not
142
+ # cycle to maximum integer when decrementing zero.
143
+ def decrement(name, amount = 1, expires_in: nil, initial: nil, **_options)
144
+ instrument :decrement, name, amount: amount do
145
+ failsafe :decrement do
146
+ key = normalize_key(name, options)
147
+ res = collection.binary.decrement(
148
+ key, ::Couchbase::Options::Decrement(delta: amount, expiry: expires_in, initial: initial)
149
+ )
150
+ @last_mutation_token = res.mutation_token
151
+ res.content
152
+ end
153
+ end
154
+ end
155
+
156
+ # Clears the entire cache. Be careful with this method since it could
157
+ # affect other processes if shared cache is being used.
158
+ #
159
+ # When +use_flush+ option set to +true+ it will flush the bucket. Otherwise, it uses N1QL query
160
+ # and relies on default index.
161
+ def clear(use_flush: false, **_options)
162
+ failsafe(:clear) do
163
+ if use_flush
164
+ cluster.buckets.flush_bucket(@couchbase_options[:bucket_name])
165
+ else
166
+ operation_options = ::Couchbase::Options::Query.new
167
+ operation_options.consistent_with(::Couchbase::MutationState.new(@last_mutation_token)) if @last_mutation_token
168
+ cluster.query("DELETE FROM #{scope_qualifier}", operation_options)
169
+ end
170
+ end
171
+ end
172
+
173
+ private
174
+
175
+ def deserialize_entry(payload, raw: false, **)
176
+ if payload && raw
177
+ Entry.new(payload, compress: false)
178
+ else
179
+ super(payload)
180
+ end
181
+ end
182
+
183
+ def serialize_entry(entry, raw: false, **options)
184
+ if raw
185
+ entry.value.to_s
186
+ else
187
+ super(entry, **options)
188
+ end
189
+ end
190
+
191
+ def serialize_entries(entries, **options)
192
+ entries.transform_values do |entry|
193
+ serialize_entry(entry, **options)
194
+ end
195
+ end
196
+
197
+ # Reads an entry from the cache
198
+ def read_entry(key, **options)
199
+ deserialize_entry(read_serialized_entry(key, **options), **options)
200
+ end
201
+
202
+ def read_serialized_entry(key, **)
203
+ failsafe(:read_entry, returning: nil) do
204
+ res = collection.get(key, ::Couchbase::Options::Get(transcoder: nil))
205
+ res.content
206
+ end
207
+ end
208
+
209
+ # Reads multiple entries from the cache implementation. Subclasses MAY
210
+ # implement this method.
211
+ def read_multi_entries(names, **options)
212
+ return {} if names.empty?
213
+
214
+ keys = names.map { |name| normalize_key(name, options) }
215
+ return_value = {}
216
+ failsafe(:read_multi_entries, returning: return_value) do
217
+ results = collection.get_multi(keys, ::Couchbase::Options::GetMulti(transcoder: nil))
218
+ results.each_with_index do |result, index|
219
+ next unless result.success?
220
+
221
+ entry = deserialize_entry(result.content, raw: options[:raw])
222
+ unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(names[index], options))
223
+ return_value[names[index]] = entry.value
224
+ end
225
+ end
226
+ return_value
227
+ end
228
+ end
229
+
230
+ # Writes an entry to the cache
231
+ def write_entry(key, entry, raw: false, **options)
232
+ write_serialized_entry(key, serialize_entry(entry, raw: raw, **options), raw: raw, **options)
233
+ end
234
+
235
+ def write_serialized_entry(key, payload, expires_in: nil, race_condition_ttl: nil, raw: false, **)
236
+ if race_condition_ttl && expires_in && expires_in.positive? && !raw
237
+ # Add few minutes to expiry in the future to support race condition TTLs on read
238
+ expires_in += 5.minutes
239
+ end
240
+ failsafe(:write_entry, returning: false) do
241
+ res = collection.upsert(key, payload, ::Couchbase::Options::Upsert(transcoder: nil, expiry: expires_in))
242
+ @last_mutation_token = res.mutation_token
243
+ true
244
+ end
245
+ end
246
+
247
+ def write_multi_entries(entries, **options)
248
+ return 0 if entries.empty?
249
+
250
+ return super if local_cache
251
+
252
+ expires_in = options[:expires_in]
253
+ if options[:race_condition_ttl] && expires_in && expires_in.positive?
254
+ # Add few minutes to expiry in the future to support race condition TTLs on read
255
+ expires_in += 5.minutes
256
+ end
257
+ operation_options = ::Couchbase::Options::UpsertMulti(transcoder: nil, expiry: expires_in)
258
+ failsafe(:write_multi_entries, returning: nil) do
259
+ successful = collection.upsert_multi(serialize_entries(entries, **options), operation_options).select(&:success?)
260
+ return 0 if successful.empty?
261
+
262
+ @last_mutation_token = successful.max_by { |r| r.mutation_token.sequence_number }
263
+ successful.count
264
+ end
265
+ end
266
+
267
+ # Deletes an entry from the cache implementation. Subclasses must
268
+ # implement this method.
269
+ def delete_entry(key, **_options)
270
+ failsafe(:delete_entry, returning: false) do
271
+ res = collection.remove(key)
272
+ @last_mutation_token = res.mutation_token
273
+ true
274
+ end
275
+ end
276
+
277
+ # Deletes multiple entries in the cache. Returns the number of entries deleted.
278
+ def delete_multi_entries(entries, **_options)
279
+ return if entries.empty?
280
+
281
+ failsafe(:delete_multi_entries, returning: nil) do
282
+ successful = collection.remove_multi(entries).select(&:success?)
283
+ return 0 if successful.empty?
284
+
285
+ @last_mutation_token = successful.max_by { |r| r.mutation_token.sequence_number }
286
+ successful.count
287
+ end
288
+ end
289
+
290
+ def failsafe(method, returning: nil)
291
+ yield
292
+ rescue ::Couchbase::Error::CouchbaseError => e
293
+ ActiveSupport.error_reporter&.report(e, handled: true, severity: :warning)
294
+ @error_handler&.call(method: method, exception: e, returning: returning)
295
+ returning
296
+ end
297
+
298
+ # Truncate keys that exceed 250 characters
299
+ def normalize_key(key, options)
300
+ truncate_key super
301
+ end
302
+
303
+ def truncate_key(key)
304
+ if key && key.bytesize > MAX_KEY_BYTESIZE
305
+ suffix = ":sha2:#{::Digest::SHA2.hexdigest(key)}"
306
+ truncate_at = MAX_KEY_BYTESIZE - suffix.bytesize
307
+ "#{key.mb_chars.limit(truncate_at)}#{suffix}"
308
+ else
309
+ key
310
+ end
311
+ end
312
+
313
+ # Connects to the Couchbase cluster
314
+ def build_cluster
315
+ ::Couchbase::Cluster.connect(
316
+ @couchbase_options[:connection_string],
317
+ ::Couchbase::Options::Cluster(authenticator: ::Couchbase::PasswordAuthenticator.new(
318
+ @couchbase_options[:username], @couchbase_options[:password]
319
+ ))
320
+ )
321
+ end
322
+
323
+ # Connects to the Couchbase cluster, opens specified bucket and returns collection object.
324
+ def build_collection
325
+ bucket = cluster.bucket(@couchbase_options[:bucket])
326
+ if @couchbase_options[:scope] && @couchbase_options[:collection]
327
+ bucket.scope(@couchbase_options[:scope]).collection(@couchbase_options[:collection])
328
+ else
329
+ bucket.default_collection
330
+ end
331
+ end
332
+
333
+ def scope_qualifier
334
+ if @couchbase_options[:scope] && @couchbase_options[:collection]
335
+ "`#{@couchbase_options[:bucket]}`.#{@couchbase_options[:scope]}.#{@couchbase_options[:collection]}"
336
+ else
337
+ "`#{@couchbase_options[:bucket]}`"
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
@@ -0,0 +1,109 @@
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/json_transcoder"
18
+
19
+ module Couchbase
20
+ class Cluster
21
+ class AnalyticsWarning
22
+ # @return [Integer]
23
+ attr_accessor :code
24
+
25
+ # @return [String]
26
+ attr_accessor :message
27
+
28
+ # @param [Integer] code
29
+ # @param [String] message
30
+ def initialize(code, message)
31
+ @code = code
32
+ @message = message
33
+ end
34
+ end
35
+
36
+ class AnalyticsMetrics
37
+ # @return [Integer] duration in milliseconds
38
+ attr_accessor :elapsed_time
39
+
40
+ # @return [Integer] duration in milliseconds
41
+ attr_accessor :execution_time
42
+
43
+ # @return [Integer]
44
+ attr_accessor :result_count
45
+
46
+ # @return [Integer]
47
+ attr_accessor :result_size
48
+
49
+ # @return [Integer]
50
+ attr_accessor :error_count
51
+
52
+ # @return [Integer]
53
+ attr_accessor :processed_objects
54
+
55
+ # @return [Integer]
56
+ attr_accessor :warning_count
57
+
58
+ # @yieldparam [AnalyticsMetrics] self
59
+ def initialize
60
+ yield self if block_given?
61
+ end
62
+ end
63
+
64
+ class AnalyticsMetaData
65
+ # @return [String]
66
+ attr_accessor :request_id
67
+
68
+ # @return [String]
69
+ attr_accessor :client_context_id
70
+
71
+ # @return [:running, :success, :errors, :completed, :stopped, :timeout, :closed, :fatal, :aborted, :unknown]
72
+ attr_accessor :status
73
+
74
+ # @return [Hash] returns the signature as returned by the query engine which is then decoded as JSON object
75
+ attr_accessor :signature
76
+
77
+ # @return [Array<AnalyticsWarning>]
78
+ attr_accessor :warnings
79
+
80
+ # @return [AnalyticsMetrics]
81
+ attr_accessor :metrics
82
+
83
+ # @yieldparam [AnalyticsMetaData] self
84
+ def initialize
85
+ yield self if block_given?
86
+ end
87
+ end
88
+
89
+ class AnalyticsResult
90
+ # @return [AnalyticsMetaData]
91
+ attr_accessor :meta_data
92
+
93
+ attr_accessor :transcoder
94
+
95
+ # Returns all rows converted using a transcoder
96
+ #
97
+ # @return [Array]
98
+ def rows(transcoder = self.transcoder)
99
+ @rows.lazy.map { |row| transcoder.decode(row, 0) }
100
+ end
101
+
102
+ # @yieldparam [AnalyticsResult] self
103
+ def initialize
104
+ @transcoder = JsonTranscoder.new
105
+ yield self if block_given?
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,66 @@
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
+ module Couchbase
18
+ # Authenticator for username/password credentials
19
+ class PasswordAuthenticator
20
+ DEFAULT_SASL_MECHANISMS = [:scram_sha512, :scram_sha256, :scram_sha1].freeze
21
+
22
+ attr_accessor :username
23
+ attr_accessor :password
24
+ attr_accessor :allowed_sasl_mechanisms
25
+
26
+ # Creates a new password authenticator with the default settings.
27
+ #
28
+ # @param [String] password the username to use for all authentication requests
29
+ # @param [String] username the password
30
+ def initialize(username, password)
31
+ @username = username
32
+ @password = password
33
+ end
34
+
35
+ # Creates a LDAP compatible password authenticator which is INSECURE if not used with TLS.
36
+ #
37
+ # Please note that this is INSECURE and will leak user credentials on the wire to eavesdroppers. This should
38
+ # only be enabled in trusted environments.
39
+ #
40
+ # @param [String] username the username to use for all authentication.
41
+ # @param [String] password the password to use alongside the username.
42
+ # @return [PasswordAuthenticator]
43
+ def self.ldap_compatible(username, password)
44
+ new(username, password).tap do |auth|
45
+ auth.allowed_sasl_mechanisms = [:plain]
46
+ end
47
+ end
48
+ end
49
+
50
+ # Authenticator for TLS client certificate
51
+ #
52
+ # @see https://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html
53
+ class CertificateAuthenticator
54
+ attr_accessor :certificate_path
55
+ attr_accessor :key_path
56
+
57
+ # Creates a new authenticator with certificate and key paths
58
+ #
59
+ # @param [String] certificate_path path to certificate
60
+ # @param [String] key_path path to private key
61
+ def initialize(certificate_path, key_path)
62
+ @certificate_path = certificate_path
63
+ @key_path = key_path
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,130 @@
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/options"
18
+ require "couchbase/binary_collection_options"
19
+
20
+ module Couchbase
21
+ # Allows to perform certain operations on non-JSON documents.
22
+ class BinaryCollection
23
+ alias inspect to_s
24
+
25
+ # @param [Couchbase::Collection] collection parent collection
26
+ def initialize(collection)
27
+ @collection = collection
28
+ @backend = collection.instance_variable_get(:@backend)
29
+ end
30
+
31
+ # Appends binary content to the document
32
+ #
33
+ # @param [String] id the document id which is used to uniquely identify it
34
+ # @param [String] content the binary content to append to the document
35
+ # @param [Options::Append] options custom options to customize the request
36
+ #
37
+ # @example Append "bar" to the content of the existing document
38
+ # collection.upsert("mydoc", "foo")
39
+ # collection.binary.append("mydoc", "bar", Options::Append(timeout: 3_000))
40
+ # collection.get("mydoc", Options::Get(transcoder: nil)).content #=> "foobar"
41
+ #
42
+ # @return [Collection::MutationResult]
43
+ def append(id, content, options = Options::Append::DEFAULT)
44
+ resp = @backend.document_append(@collection.bucket_name, @collection.scope_name, @collection.name,
45
+ id, content, options.to_backend)
46
+ Collection::MutationResult.new do |res|
47
+ res.cas = resp[:cas]
48
+ res.mutation_token = @collection.send(:extract_mutation_token, resp)
49
+ end
50
+ end
51
+
52
+ # Prepends binary content to the document
53
+ #
54
+ # @param [String] id the document id which is used to uniquely identify it
55
+ # @param [String] content the binary content to prepend to the document
56
+ # @param [Options::Prepend] options custom options to customize the request
57
+ #
58
+ # @example Prepend "bar" to the content of the existing document
59
+ # collection.upsert("mydoc", "foo")
60
+ # collection.binary.prepend("mydoc", "bar", Options::Prepend(timeout: 3_000))
61
+ # collection.get("mydoc", Options::Get(transcoder: nil)).content #=> "barfoo"
62
+ #
63
+ # @return [Collection::MutationResult]
64
+ def prepend(id, content, options = Options::Prepend::DEFAULT)
65
+ resp = @backend.document_prepend(@collection.bucket_name, @collection.scope_name, @collection.name,
66
+ id, content, options.to_backend)
67
+ Collection::MutationResult.new do |res|
68
+ res.cas = resp[:cas]
69
+ res.mutation_token = @collection.send(:extract_mutation_token, resp)
70
+ end
71
+ end
72
+
73
+ # Increments the counter document by one of the number defined in the options
74
+ #
75
+ # @param [String] id the document id which is used to uniquely identify it
76
+ # @param [Options::Increment] options custom options to customize the request
77
+ #
78
+ # @example Increment value by 10, and initialize to 0 if it does not exist
79
+ # res = collection.binary.increment("raw_counter", Options::Increment(delta: 10, initial: 0))
80
+ # res.content #=> 0
81
+ # res = collection.binary.increment("raw_counter", Options::Increment(delta: 10, initial: 0))
82
+ # res.content #=> 10
83
+ #
84
+ # @return [CounterResult]
85
+ def increment(id, options = Options::Increment::DEFAULT)
86
+ resp = @backend.document_increment(@collection.bucket_name, @collection.scope_name, @collection.name, id,
87
+ options.to_backend)
88
+ CounterResult.new do |res|
89
+ res.cas = resp[:cas]
90
+ res.content = resp[:content]
91
+ res.mutation_token = @collection.send(:extract_mutation_token, resp)
92
+ end
93
+ end
94
+
95
+ # Decrements the counter document by one of the number defined in the options
96
+ #
97
+ # @param [String] id the document id which is used to uniquely identify it
98
+ # @param [Options::Decrement] options custom options to customize the request
99
+ #
100
+ # @example Decrement value by 2, and initialize to 100 if it does not exist
101
+ # res = collection.binary.decrement("raw_counter", Options::Decrement(delta: 2, initial: 100))
102
+ # res.value #=> 100
103
+ # res = collection.binary.decrement("raw_counter", Options::Decrement(delta: 2, initial: 100))
104
+ # res.value #=> 98
105
+ #
106
+ # @return [CounterResult]
107
+ def decrement(id, options = Options::Decrement::DEFAULT)
108
+ resp = @backend.document_decrement(@collection.bucket_name, @collection.scope_name, @collection.name, id,
109
+ options.to_backend)
110
+ CounterResult.new do |res|
111
+ res.cas = resp[:cas]
112
+ res.content = resp[:content]
113
+ res.mutation_token = @collection.send(:extract_mutation_token, resp)
114
+ end
115
+ end
116
+
117
+ # @api private
118
+ # TODO: deprecate in 3.1
119
+ AppendOptions = ::Couchbase::Options::Append
120
+ # @api private
121
+ # TODO: deprecate in 3.1
122
+ PrependOptions = ::Couchbase::Options::Prepend
123
+ # @api private
124
+ # TODO: deprecate in 3.1
125
+ IncrementOptions = ::Couchbase::Options::Increment
126
+ # @api private
127
+ # TODO: deprecate in 3.1
128
+ DecrementOptions = ::Couchbase::Options::Decrement
129
+ end
130
+ end
@@ -0,0 +1,26 @@
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/collection_options"
18
+
19
+ module Couchbase
20
+ class BinaryCollection
21
+ class CounterResult < ::Couchbase::Collection::MutationResult
22
+ # @return [Integer] current value of the counter
23
+ attr_accessor :content
24
+ end
25
+ end
26
+ end