couchbase-jruby-client 0.1.1

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