couchbase-jruby-client 0.1.0-java

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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +203 -0
  6. data/README.md +347 -0
  7. data/Rakefile +10 -0
  8. data/couchbase-jruby-client.gemspec +30 -0
  9. data/lib/couchbase/async/callback.rb +19 -0
  10. data/lib/couchbase/async/queue.rb +26 -0
  11. data/lib/couchbase/async.rb +139 -0
  12. data/lib/couchbase/bucket.rb +663 -0
  13. data/lib/couchbase/cluster.rb +105 -0
  14. data/lib/couchbase/constants.rb +12 -0
  15. data/lib/couchbase/error.rb +28 -0
  16. data/lib/couchbase/jruby/couchbase_client.rb +22 -0
  17. data/lib/couchbase/jruby/future.rb +8 -0
  18. data/lib/couchbase/operations/arithmetic.rb +301 -0
  19. data/lib/couchbase/operations/delete.rb +104 -0
  20. data/lib/couchbase/operations/get.rb +298 -0
  21. data/lib/couchbase/operations/stats.rb +16 -0
  22. data/lib/couchbase/operations/store.rb +468 -0
  23. data/lib/couchbase/operations/touch.rb +123 -0
  24. data/lib/couchbase/operations/utils.rb +49 -0
  25. data/lib/couchbase/operations.rb +23 -0
  26. data/lib/couchbase/result.rb +43 -0
  27. data/lib/couchbase/transcoder.rb +83 -0
  28. data/lib/couchbase/utils.rb +62 -0
  29. data/lib/couchbase/version.rb +3 -0
  30. data/lib/couchbase/view.rb +506 -0
  31. data/lib/couchbase/view_row.rb +272 -0
  32. data/lib/couchbase.rb +177 -0
  33. data/lib/jars/commons-codec-1.5.jar +0 -0
  34. data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
  35. data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
  36. data/lib/jars/couchbase-client-1.2.0.jar +0 -0
  37. data/lib/jars/httpcore-4.1.1.jar +0 -0
  38. data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
  39. data/lib/jars/jettison-1.1.jar +0 -0
  40. data/lib/jars/netty-3.5.5.Final.jar +0 -0
  41. data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
  42. data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
  43. data/lib/jars/spymemcached-2.10.0.jar +0 -0
  44. data/test/profile/.gitignore +1 -0
  45. data/test/profile/Gemfile +6 -0
  46. data/test/profile/benchmark.rb +195 -0
  47. data/test/setup.rb +201 -0
  48. data/test/test_arithmetic.rb +177 -0
  49. data/test/test_async.rb +324 -0
  50. data/test/test_bucket.rb +213 -0
  51. data/test/test_cas.rb +78 -0
  52. data/test/test_couchbase.rb +29 -0
  53. data/test/test_couchbase_rails_cache_store.rb +341 -0
  54. data/test/test_delete.rb +125 -0
  55. data/test/test_errors.rb +82 -0
  56. data/test/test_format.rb +161 -0
  57. data/test/test_get.rb +417 -0
  58. data/test/test_stats.rb +57 -0
  59. data/test/test_store.rb +216 -0
  60. data/test/test_timer.rb +42 -0
  61. data/test/test_touch.rb +97 -0
  62. data/test/test_unlock.rb +119 -0
  63. data/test/test_utils.rb +58 -0
  64. data/test/test_version.rb +52 -0
  65. metadata +226 -0
@@ -0,0 +1,468 @@
1
+ module Couchbase::Operations
2
+ module Store
3
+
4
+ # Unconditionally store the object in the Couchbase
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ # @overload set(key, value, options = {})
9
+ #
10
+ # @param key [String, Symbol] Key used to reference the value.
11
+ # @param value [Object] Value to be stored
12
+ # @param options [Hash] Options for operation.
13
+ # @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
14
+ # Values larger than 30*24*60*60 seconds (30 days) are interpreted as
15
+ # absolute times (from the epoch).
16
+ # @option options [Fixnum] :flags (self.default_flags) Flags for storage
17
+ # options. Flags are ignored by the server but preserved for use by the
18
+ # client. For more info see {Bucket#default_flags}.
19
+ # @option options [Symbol] :format (self.default_format) The
20
+ # representation for storing the value in the bucket. For more info see
21
+ # {Bucket#default_format}.
22
+ # @option options [Fixnum] :cas The CAS value for an object. This value is
23
+ # created on the server and is guaranteed to be unique for each value of
24
+ # a given key. This value is used to provide simple optimistic
25
+ # concurrency control when multiple clients or threads try to update an
26
+ # item simultaneously.
27
+ # @option options [Hash] :observe Apply persistence condition before
28
+ # returning result. When this option specified the library will observe
29
+ # given condition. See {Bucket#observe_and_wait}.
30
+ #
31
+ # @yieldparam ret [Result] the result of operation in asynchronous mode
32
+ # (valid attributes: +error+, +operation+, +key+).
33
+ #
34
+ # @return [Fixnum] The CAS value of the object.
35
+ #
36
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect}).
37
+ # @raise [Couchbase::Error::KeyExists] if the key already exists on the
38
+ # server.
39
+ # @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
40
+ # with chosen encoder, e.g. if you try to store the Hash in +:plain+
41
+ # mode.
42
+ # @raise [ArgumentError] when passing the block in synchronous mode
43
+ # @raise [Couchbase::Error::Timeout] if timeout interval for observe
44
+ # exceeds
45
+ #
46
+ # @example Store the key which will be expired in 2 seconds using relative TTL.
47
+ # c.set("foo", "bar", :ttl => 2)
48
+ #
49
+ # @example Perform multi-set operation. It takes a Hash store its keys/values into the bucket
50
+ # c.set("foo1" => "bar1", "foo2" => "bar2")
51
+ # #=> {"foo1" => cas1, "foo2" => cas2}
52
+ #
53
+ # @example More advanced multi-set using asynchronous mode
54
+ # c.run do
55
+ # # fire and forget
56
+ # c.set("foo1", "bar1", :ttl => 10)
57
+ # # receive result into the callback
58
+ # c.set("foo2", "bar2", :ttl => 10) do |ret|
59
+ # if ret.success?
60
+ # puts ret.cas
61
+ # end
62
+ # end
63
+ # end
64
+ #
65
+ # @example Store the key which will be expired in 2 seconds using absolute TTL.
66
+ # c.set("foo", "bar", :ttl => Time.now.to_i + 2)
67
+ #
68
+ # @example Force JSON document format for value
69
+ # c.set("foo", {"bar" => "baz}, :format => :document)
70
+ #
71
+ # @example Use hash-like syntax to store the value
72
+ # c["foo"] = {"bar" => "baz}
73
+ #
74
+ # @example Use extended hash-like syntax
75
+ # c["foo", {:flags => 0x1000, :format => :plain}] = "bar"
76
+ # c["foo", :flags => 0x1000] = "bar" # for ruby 1.9.x only
77
+ #
78
+ # @example Set application specific flags (note that it will be OR-ed with format flags)
79
+ # c.set("foo", "bar", :flags => 0x1000)
80
+ #
81
+ # @example Perform optimistic locking by specifying last known CAS version
82
+ # c.set("foo", "bar", :cas => 8835713818674332672)
83
+ #
84
+ # @example Perform asynchronous call
85
+ # c.run do
86
+ # c.set("foo", "bar") do |ret|
87
+ # ret.operation #=> :set
88
+ # ret.success? #=> true
89
+ # ret.key #=> "foo"
90
+ # ret.cas
91
+ # end
92
+ # end
93
+ #
94
+ # @example Ensure that the key will be persisted at least on the one node
95
+ # c.set("foo", "bar", :observe => {:persisted => 1})
96
+ #
97
+ def set(key, value = nil, options = {}, &block)
98
+ sync_block_error if !async? && block_given?
99
+ op, key, value, ttl = store_args_parser(key, value, options)
100
+
101
+ if op == :single
102
+ set_single(key, value, ttl, options, &block)
103
+ else
104
+ set_multi(key)
105
+ end
106
+ end
107
+
108
+ def []=(key, *args)
109
+ options = args.size > 1 ? args.shift : {}
110
+ value = args.pop
111
+
112
+ set(key, value, options)
113
+ end
114
+
115
+ # Add the item to the database, but fail if the object exists already
116
+ #
117
+ # @since 1.0.0
118
+ #
119
+ # @overload add(key, value, options = {})
120
+ #
121
+ # @param key [String, Symbol] Key used to reference the value.
122
+ # @param value [Object] Value to be stored
123
+ # @param options [Hash] Options for operation.
124
+ # @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
125
+ # Values larger than 30*24*60*60 seconds (30 days) are interpreted as
126
+ # absolute times (from the epoch).
127
+ # @option options [Fixnum] :flags (self.default_flags) Flags for storage
128
+ # options. Flags are ignored by the server but preserved for use by the
129
+ # client. For more info see {Bucket#default_flags}.
130
+ # @option options [Symbol] :format (self.default_format) The
131
+ # representation for storing the value in the bucket. For more info see
132
+ # {Bucket#default_format}.
133
+ # @option options [Fixnum] :cas The CAS value for an object. This value
134
+ # created on the server and is guaranteed to be unique for each value of
135
+ # a given key. This value is used to provide simple optimistic
136
+ # concurrency control when multiple clients or threads try to update an
137
+ # item simultaneously.
138
+ # @option options [Hash] :observe Apply persistence condition before
139
+ # returning result. When this option specified the library will observe
140
+ # given condition. See {Bucket#observe_and_wait}.
141
+ #
142
+ # @yieldparam ret [Result] the result of operation in asynchronous mode
143
+ # (valid attributes: +error+, +operation+, +key+).
144
+ #
145
+ # @return [Fixnum] The CAS value of the object.
146
+ #
147
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
148
+ # @raise [Couchbase::Error::KeyExists] if the key already exists on the
149
+ # server
150
+ # @raise [Couchbase::Error::ValueFormat] if the value cannot be serialized
151
+ # with chosen encoder, e.g. if you try to store the Hash in +:plain+
152
+ # mode.
153
+ # @raise [ArgumentError] when passing the block in synchronous mode
154
+ # @raise [Couchbase::Error::Timeout] if timeout interval for observe
155
+ # exceeds
156
+ #
157
+ # @example Add the same key twice
158
+ # c.add("foo", "bar") #=> stored successully
159
+ # c.add("foo", "baz") #=> will raise Couchbase::Error::KeyExists: failed to store value (key="foo", error=0x0c)
160
+ #
161
+ # @example Ensure that the key will be persisted at least on the one node
162
+ # c.add("foo", "bar", :observe => {:persisted => 1})
163
+ #
164
+ def add(key, value = nil, options = {}, &block)
165
+ sync_block_error if !async? && block_given?
166
+ op, key, value, ttl = store_args_parser(key, value, options)
167
+
168
+ if op == :single
169
+ add_single(key, value, ttl, options, &block)
170
+ else
171
+ add_multi(key)
172
+ end
173
+ end
174
+
175
+ # Replace the existing object in the database
176
+ #
177
+ # @since 1.0.0
178
+ #
179
+ # @overload replace(key, value, options = {})
180
+ # @param key [String, Symbol] Key used to reference the value.
181
+ # @param value [Object] Value to be stored
182
+ # @param options [Hash] Options for operation.
183
+ # @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
184
+ # Values larger than 30*24*60*60 seconds (30 days) are interpreted as
185
+ # absolute times (from the epoch).
186
+ # @option options [Fixnum] :flags (self.default_flags) Flags for storage
187
+ # options. Flags are ignored by the server but preserved for use by the
188
+ # client. For more info see {Bucket#default_flags}.
189
+ # @option options [Symbol] :format (self.default_format) The
190
+ # representation for storing the value in the bucket. For more info see
191
+ # {Bucket#default_format}.
192
+ # @option options [Fixnum] :cas The CAS value for an object. This value
193
+ # created on the server and is guaranteed to be unique for each value of
194
+ # a given key. This value is used to provide simple optimistic
195
+ # concurrency control when multiple clients or threads try to update an
196
+ # item simultaneously.
197
+ # @option options [Hash] :observe Apply persistence condition before
198
+ # returning result. When this option specified the library will observe
199
+ # given condition. See {Bucket#observe_and_wait}.
200
+ #
201
+ # @return [Fixnum] The CAS value of the object.
202
+ #
203
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
204
+ # @raise [Couchbase::Error::NotFound] if the key doesn't exists
205
+ # @raise [Couchbase::Error::KeyExists] on CAS mismatch
206
+ # @raise [ArgumentError] when passing the block in synchronous mode
207
+ # @raise [Couchbase::Error::Timeout] if timeout interval for observe
208
+ # exceeds
209
+ #
210
+ # @example Replacing missing key
211
+ # c.replace("foo", "baz") #=> will raise Couchbase::Error::NotFound: failed to store value (key="foo", error=0x0d)
212
+ #
213
+ # @example Ensure that the key will be persisted at least on the one node
214
+ # c.replace("foo", "bar", :observe => {:persisted => 1})
215
+ #
216
+ def replace(key, value, options = {})
217
+ sync_block_error if !async? && block_given?
218
+ if cas = java_replace(key, value, options[:ttl])
219
+ cas
220
+ else
221
+ raise Couchbase::Error::NotFound.new
222
+ end
223
+ end
224
+
225
+ # Append this object to the existing object
226
+ #
227
+ # @since 1.0.0
228
+ #
229
+ # @note This operation is kind of data-aware from server point of view.
230
+ # This mean that the server treats value as binary stream and just
231
+ # perform concatenation, therefore it won't work with +:marshal+ and
232
+ # +:document+ formats, because of lack of knowledge how to merge values
233
+ # in these formats. See {Bucket#cas} for workaround.
234
+ #
235
+ # @overload append(key, value, options = {})
236
+ # @param key [String, Symbol] Key used to reference the value.
237
+ # @param value [Object] Value to be stored
238
+ # @param options [Hash] Options for operation.
239
+ # @option options [Fixnum] :cas The CAS value for an object. This value
240
+ # created on the server and is guaranteed to be unique for each value of
241
+ # a given key. This value is used to provide simple optimistic
242
+ # concurrency control when multiple clients or threads try to update an
243
+ # item simultaneously.
244
+ # @option options [Symbol] :format (self.default_format) The
245
+ # representation for storing the value in the bucket. For more info see
246
+ # {Bucket#default_format}.
247
+ # @option options [Hash] :observe Apply persistence condition before
248
+ # returning result. When this option specified the library will observe
249
+ # given condition. See {Bucket#observe_and_wait}.
250
+ #
251
+ # @return [Fixnum] The CAS value of the object.
252
+ #
253
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
254
+ # @raise [Couchbase::Error::KeyExists] on CAS mismatch
255
+ # @raise [Couchbase::Error::NotStored] if the key doesn't exist
256
+ # @raise [ArgumentError] when passing the block in synchronous mode
257
+ # @raise [Couchbase::Error::Timeout] if timeout interval for observe
258
+ # exceeds
259
+ #
260
+ # @example Simple append
261
+ # c.set("foo", "aaa")
262
+ # c.append("foo", "bbb")
263
+ # c.get("foo") #=> "aaabbb"
264
+ #
265
+ # @example Implementing sets using append
266
+ # def set_add(key, *values)
267
+ # encoded = values.flatten.map{|v| "+#{v} "}.join
268
+ # append(key, encoded)
269
+ # end
270
+ #
271
+ # def set_remove(key, *values)
272
+ # encoded = values.flatten.map{|v| "-#{v} "}.join
273
+ # append(key, encoded)
274
+ # end
275
+ #
276
+ # def set_get(key)
277
+ # encoded = get(key)
278
+ # ret = Set.new
279
+ # encoded.split(' ').each do |v|
280
+ # op, val = v[0], v[1..-1]
281
+ # case op
282
+ # when "-"
283
+ # ret.delete(val)
284
+ # when "+"
285
+ # ret.add(val)
286
+ # end
287
+ # end
288
+ # ret
289
+ # end
290
+ #
291
+ # @example Using optimistic locking. The operation will fail on CAS mismatch
292
+ # ver = c.set("foo", "aaa")
293
+ # c.append("foo", "bbb", :cas => ver)
294
+ #
295
+ # @example Ensure that the key will be persisted at least on the one node
296
+ # c.append("foo", "bar", :observe => {:persisted => 1})
297
+ #
298
+ def append(key, value)
299
+ sync_block_error if !async? && block_given?
300
+ if cas = java_append(validate_key(key), value)
301
+ cas
302
+ else
303
+ raise Couchbase::Error::NotFound.new
304
+ end
305
+ end
306
+
307
+ # Prepend this object to the existing object
308
+ #
309
+ # @since 1.0.0
310
+ #
311
+ # @note This operation is kind of data-aware from server point of view.
312
+ # This mean that the server treats value as binary stream and just
313
+ # perform concatenation, therefore it won't work with +:marshal+ and
314
+ # +:document+ formats, because of lack of knowledge how to merge values
315
+ # in these formats. See {Bucket#cas} for workaround.
316
+ #
317
+ # @overload prepend(key, value, options = {})
318
+ # @param key [String, Symbol] Key used to reference the value.
319
+ # @param value [Object] Value to be stored
320
+ # @param options [Hash] Options for operation.
321
+ # @option options [Fixnum] :cas The CAS value for an object. This value
322
+ # created on the server and is guaranteed to be unique for each value of
323
+ # a given key. This value is used to provide simple optimistic
324
+ # concurrency control when multiple clients or threads try to update an
325
+ # item simultaneously.
326
+ # @option options [Symbol] :format (self.default_format) The
327
+ # representation for storing the value in the bucket. For more info see
328
+ # {Bucket#default_format}.
329
+ # @option options [Hash] :observe Apply persistence condition before
330
+ # returning result. When this option specified the library will observe
331
+ # given condition. See {Bucket#observe_and_wait}.
332
+ #
333
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
334
+ # @raise [Couchbase::Error::KeyExists] on CAS mismatch
335
+ # @raise [Couchbase::Error::NotStored] if the key doesn't exist
336
+ # @raise [ArgumentError] when passing the block in synchronous mode
337
+ # @raise [Couchbase::Error::Timeout] if timeout interval for observe
338
+ # exceeds
339
+ #
340
+ # @example Simple prepend example
341
+ # c.set("foo", "aaa")
342
+ # c.prepend("foo", "bbb")
343
+ # c.get("foo") #=> "bbbaaa"
344
+ #
345
+ # @example Using explicit format option
346
+ # c.default_format #=> :document
347
+ # c.set("foo", {"y" => "z"})
348
+ # c.prepend("foo", '[', :format => :plain)
349
+ # c.append("foo", ', {"z": "y"}]', :format => :plain)
350
+ # c.get("foo") #=> [{"y"=>"z"}, {"z"=>"y"}]
351
+ #
352
+ # @example Using optimistic locking. The operation will fail on CAS mismatch
353
+ # ver = c.set("foo", "aaa")
354
+ # c.prepend("foo", "bbb", :cas => ver)
355
+ #
356
+ # @example Ensure that the key will be persisted at least on the one node
357
+ # c.prepend("foo", "bar", :observe => {:persisted => 1})
358
+ #
359
+ def prepend(*args)
360
+ sync_block_error if !async? && block_given?
361
+ end
362
+
363
+ private
364
+
365
+ def store_args_parser(key, value, options)
366
+ key = key.to_str if key.respond_to?(:to_str)
367
+ ttl = options[:ttl] || default_ttl
368
+
369
+ op = case key
370
+ when String, Symbol
371
+ :single
372
+ when Hash
373
+ raise TypeError.new if !value.nil?
374
+ :multi
375
+ else
376
+ raise TypeError.new
377
+ end
378
+
379
+ [op, key, value, ttl]
380
+ end
381
+
382
+ def set_single(key, value, ttl, options = {}, &block)
383
+ if async?
384
+ java_async_set(key, value, ttl, &block)
385
+ else
386
+ if options[:cas]
387
+ if java_set_cas(key, value, ttl, options[:cas])
388
+ get(key, extended: true)[2]
389
+ else
390
+ raise Couchbase::Error::KeyExists.new
391
+ end
392
+ else
393
+ if cas = java_set(key, value, ttl)
394
+ cas
395
+ else
396
+ raise Couchbase::Error::KeyExists.new
397
+ end
398
+ end
399
+ end
400
+ end
401
+
402
+ def add_single(key, value, ttl, options = {})
403
+ if async?
404
+ java_async_set(key, value, ttl, &Proc.new)
405
+ else
406
+ if cas = java_add(key, value, ttl)
407
+ cas
408
+ else
409
+ raise Couchbase::Error::KeyExists.new
410
+ end
411
+ end
412
+ end
413
+
414
+ # TODO:
415
+ def set_multi(keys)
416
+ {}.tap do |results|
417
+ keys.each_pair do |key, value|
418
+ results[key] = java_set(key, value, default_ttl)
419
+ end
420
+ end
421
+ end
422
+
423
+ def add_multi(keys)
424
+ {}.tap do |results|
425
+ keys.each_pair do |key, value|
426
+ results[key] = java_add(key, value, default_ttl)
427
+ end
428
+ end
429
+ end
430
+
431
+ def java_set(key, value, ttl)
432
+ future = client.set(key.to_s, ttl, dump(value))
433
+ future_cas(future)
434
+ end
435
+
436
+ def java_add(key, value, ttl)
437
+ future = client.add(key.to_s, ttl, dump(value))
438
+ future_cas(future)
439
+ end
440
+
441
+ def java_replace(key, value, ttl)
442
+ future = if ttl.nil?
443
+ client.replace(key.to_s, dump(value))
444
+ else
445
+ client.replace(key.to_s, ttl, dump(value))
446
+ end
447
+
448
+ future_cas(future)
449
+ end
450
+
451
+ def java_append(key, value)
452
+ future = client.append(key.to_s, dump(value))
453
+ future_cas(future)
454
+ end
455
+
456
+ def java_set_cas(key, value, ttl, cas)
457
+ cas_response = client.cas(key.to_s, cas, ttl, dump(value))
458
+ cas_response.to_s == 'OK'
459
+ end
460
+
461
+ def java_async_set(key, value, ttl, &block)
462
+ future = client.set(key.to_s, ttl, dump(value))
463
+ register_future(future, { op: :set }, &block)
464
+ end
465
+
466
+ end
467
+
468
+ end
@@ -0,0 +1,123 @@
1
+ module Couchbase::Operations
2
+ module Touch
3
+
4
+ # Update the expiry time of an item
5
+ #
6
+ # @since 1.0.0
7
+ #
8
+ # The +touch+ method allow you to update the expiration time on a given
9
+ # key. This can be useful for situations where you want to prevent an item
10
+ # from expiring without resetting the associated value. For example, for a
11
+ # session database you might want to keep the session alive in the database
12
+ # each time the user accesses a web page without explicitly updating the
13
+ # session value, keeping the user's session active and available.
14
+ #
15
+ # @overload touch(key, options = {})
16
+ # @param key [String, Symbol] Key used to reference the value.
17
+ # @param options [Hash] Options for operation.
18
+ # @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
19
+ # Values larger than 30*24*60*60 seconds (30 days) are interpreted as
20
+ # absolute times (from the epoch).
21
+ # @option options [true, false] :quiet (self.quiet) If set to +true+, the
22
+ # operation won't raise error for missing key, it will return +nil+.
23
+ #
24
+ # @yieldparam ret [Result] the result of operation in asynchronous mode
25
+ # (valid attributes: +error+, +operation+, +key+).
26
+ #
27
+ # @return [true, false] +true+ if the operation was successful and +false+
28
+ # otherwise.
29
+ #
30
+ # @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
31
+ #
32
+ # @raise [ArgumentError] when passing the block in synchronous mode
33
+ #
34
+ # @example Touch value using +default_ttl+
35
+ # c.touch("foo")
36
+ #
37
+ # @example Touch value using custom TTL (10 seconds)
38
+ # c.touch("foo", :ttl => 10)
39
+ #
40
+ # @overload touch(keys)
41
+ # @param keys [Hash] The Hash where keys represent the keys in the
42
+ # database, values -- the expiry times for corresponding key. See
43
+ # description of +:ttl+ argument above for more information about TTL
44
+ # values.
45
+ #
46
+ # @yieldparam ret [Result] the result of operation for each key in
47
+ # asynchronous mode (valid attributes: +error+, +operation+, +key+).
48
+ #
49
+ # @return [Hash] Mapping keys to result of touch operation (+true+ if the
50
+ # operation was successful and +false+ otherwise)
51
+ #
52
+ # @example Touch several values
53
+ # c.touch("foo" => 10, :bar => 20) #=> {"foo" => true, "bar" => true}
54
+ #
55
+ # @example Touch several values in async mode
56
+ # c.run do
57
+ # c.touch("foo" => 10, :bar => 20) do |ret|
58
+ # ret.operation #=> :touch
59
+ # ret.success? #=> true
60
+ # ret.key #=> "foo" and "bar" in separate calls
61
+ # end
62
+ # end
63
+ #
64
+ # @example Touch single value
65
+ # c.touch("foo" => 10) #=> true
66
+ #
67
+ def touch(*args, &block)
68
+ sync_block_error if !async? && block_given?
69
+ key, options = expand_touch_args(args)
70
+
71
+ if key.respond_to?(:to_hash)
72
+ multi_touch_hash(key, options)
73
+ elsif key.respond_to?(:to_ary)
74
+ multi_touch_array(key, options)
75
+ else
76
+ if async?
77
+ java_async_touch(key, options[:ttl], &block)
78
+ else
79
+ success = java_touch(key, options[:ttl])
80
+ not_found_error(!success, options)
81
+ success
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def expand_touch_args(args)
89
+ options = extract_options_hash(args)
90
+ options[:ttl] ||= args.size > 1 ? args.pop : default_ttl
91
+ key = args.pop
92
+
93
+ [key, options]
94
+ end
95
+
96
+ def multi_touch_hash(keys, options = {})
97
+ {}.tap do |results|
98
+ keys.each_pair do |key, ttl|
99
+ results[key] = java_touch(key, ttl)
100
+ end
101
+ end
102
+ end
103
+
104
+ def multi_touch_array(keys, options = {})
105
+ ttl = options[:ttl] || default_ttl
106
+
107
+ {}.tap do |results|
108
+ keys.each do |key|
109
+ results[key] = java_touch(key, ttl)
110
+ end
111
+ end
112
+ end
113
+
114
+ def java_touch(key, ttl, options = {})
115
+ client.touch(key, ttl).get
116
+ end
117
+
118
+ def java_async_touch(key, ttl, &block)
119
+ register_future(client.touch(key, ttl), { op: :touch }, &block)
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,49 @@
1
+ module Couchbase::Operations
2
+ module Utils
3
+
4
+ private
5
+
6
+ def validate_key(key)
7
+ if key_prefix
8
+ "#{key_prefix}key"
9
+ else
10
+ key.to_s
11
+ end
12
+ end
13
+
14
+ def extract_options_hash(args)
15
+ if args.size > 1 && args.last.respond_to?(:to_hash)
16
+ args.pop
17
+ else
18
+ {}
19
+ end
20
+ end
21
+
22
+ def sync_block_error
23
+ raise ArgumentError, "synchronous mode doesn't support callbacks"
24
+ end
25
+
26
+ def not_found_error(error, options = {})
27
+ if error
28
+ if options.key?(:quiet)
29
+ raise Error::NotFound.new if !options[:quiet]
30
+ elsif !quiet?
31
+ raise Error::NotFound.new
32
+ end
33
+ end
34
+ end
35
+
36
+ def future_cas(future)
37
+ future.get && future.getCas
38
+ end
39
+
40
+ def dump(obj)
41
+ transcoder.dump(obj)
42
+ end
43
+
44
+ def load(blob)
45
+ transcoder.load(blob)
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ require 'couchbase/operations/touch'
2
+ require 'couchbase/operations/store'
3
+ require 'couchbase/operations/get'
4
+ require 'couchbase/operations/delete'
5
+ require 'couchbase/operations/arithmetic'
6
+ require 'couchbase/operations/stats'
7
+ require 'couchbase/operations/utils'
8
+
9
+ module Couchbase
10
+ module Operations
11
+
12
+ def self.included(klass)
13
+ klass.send(:include, Store)
14
+ klass.send(:include, Get)
15
+ klass.send(:include, Touch)
16
+ klass.send(:include, Delete)
17
+ klass.send(:include, Arithmetic)
18
+ klass.send(:include, Stats)
19
+ klass.send(:include, Utils)
20
+ end
21
+ end
22
+ end
23
+