redis 4.6.0 → 5.0.4

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -1
  3. data/README.md +75 -146
  4. data/lib/redis/client.rb +92 -608
  5. data/lib/redis/commands/bitmaps.rb +4 -1
  6. data/lib/redis/commands/cluster.rb +1 -18
  7. data/lib/redis/commands/connection.rb +5 -10
  8. data/lib/redis/commands/geo.rb +3 -3
  9. data/lib/redis/commands/hashes.rb +8 -5
  10. data/lib/redis/commands/hyper_log_log.rb +1 -1
  11. data/lib/redis/commands/keys.rb +53 -27
  12. data/lib/redis/commands/lists.rb +19 -23
  13. data/lib/redis/commands/pubsub.rb +7 -25
  14. data/lib/redis/commands/server.rb +15 -15
  15. data/lib/redis/commands/sets.rb +43 -36
  16. data/lib/redis/commands/sorted_sets.rb +27 -13
  17. data/lib/redis/commands/streams.rb +12 -10
  18. data/lib/redis/commands/strings.rb +16 -15
  19. data/lib/redis/commands/transactions.rb +26 -3
  20. data/lib/redis/commands.rb +1 -8
  21. data/lib/redis/distributed.rb +100 -67
  22. data/lib/redis/errors.rb +14 -41
  23. data/lib/redis/hash_ring.rb +26 -26
  24. data/lib/redis/pipeline.rb +56 -203
  25. data/lib/redis/subscribe.rb +23 -15
  26. data/lib/redis/version.rb +1 -1
  27. data/lib/redis.rb +90 -178
  28. metadata +9 -53
  29. data/lib/redis/cluster/command.rb +0 -79
  30. data/lib/redis/cluster/command_loader.rb +0 -33
  31. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  32. data/lib/redis/cluster/node.rb +0 -120
  33. data/lib/redis/cluster/node_key.rb +0 -31
  34. data/lib/redis/cluster/node_loader.rb +0 -37
  35. data/lib/redis/cluster/option.rb +0 -93
  36. data/lib/redis/cluster/slot.rb +0 -86
  37. data/lib/redis/cluster/slot_loader.rb +0 -49
  38. data/lib/redis/cluster.rb +0 -315
  39. data/lib/redis/connection/command_helper.rb +0 -41
  40. data/lib/redis/connection/hiredis.rb +0 -68
  41. data/lib/redis/connection/registry.rb +0 -13
  42. data/lib/redis/connection/ruby.rb +0 -431
  43. data/lib/redis/connection/synchrony.rb +0 -148
  44. data/lib/redis/connection.rb +0 -11
@@ -60,8 +60,11 @@ class Redis
60
60
  command << "INCR" if incr
61
61
 
62
62
  if args.size == 1 && args[0].is_a?(Array)
63
+ members_to_add = args[0]
64
+ return 0 if members_to_add.empty?
65
+
63
66
  # Variadic: return float if INCR, integer if !INCR
64
- send_command(command + args[0], &(incr ? Floatify : nil))
67
+ send_command(command + members_to_add, &(incr ? Floatify : nil))
65
68
  elsif args.size == 2
66
69
  # Single pair: return float if INCR, boolean if !INCR
67
70
  send_command(command + args, &(incr ? Floatify : Boolify))
@@ -102,6 +105,11 @@ class Redis
102
105
  # - `Integer` when an array of pairs is specified, holding the number of
103
106
  # members that were removed to the sorted set
104
107
  def zrem(key, member)
108
+ if member.is_a?(Array)
109
+ members_to_remove = member
110
+ return 0 if members_to_remove.empty?
111
+ end
112
+
105
113
  send_command([:zrem, key, member]) do |reply|
106
114
  if member.is_a? Array
107
115
  # Variadic: return integer
@@ -128,7 +136,9 @@ class Redis
128
136
  # @return [Array<String, Float>] element and score pair if count is not specified
129
137
  # @return [Array<Array<String, Float>>] list of popped elements and scores
130
138
  def zpopmax(key, count = nil)
131
- send_command([:zpopmax, key, count].compact) do |members|
139
+ command = [:zpopmax, key]
140
+ command << Integer(count) if count
141
+ send_command(command) do |members|
132
142
  members = FloatifyPairs.call(members)
133
143
  count.to_i > 1 ? members : members.first
134
144
  end
@@ -149,7 +159,9 @@ class Redis
149
159
  # @return [Array<String, Float>] element and score pair if count is not specified
150
160
  # @return [Array<Array<String, Float>>] list of popped elements and scores
151
161
  def zpopmin(key, count = nil)
152
- send_command([:zpopmin, key, count].compact) do |members|
162
+ command = [:zpopmin, key]
163
+ command << Integer(count) if count
164
+ send_command(command) do |members|
153
165
  members = FloatifyPairs.call(members)
154
166
  count.to_i > 1 ? members : members.first
155
167
  end
@@ -253,7 +265,7 @@ class Redis
253
265
  end
254
266
 
255
267
  args = [:zrandmember, key]
256
- args << count if count
268
+ args << Integer(count) if count
257
269
 
258
270
  if with_scores
259
271
  args << "WITHSCORES"
@@ -305,7 +317,7 @@ class Redis
305
317
 
306
318
  if limit
307
319
  args << "LIMIT"
308
- args.concat(limit)
320
+ args.concat(limit.map { |l| Integer(l) })
309
321
  end
310
322
 
311
323
  if with_scores
@@ -346,7 +358,7 @@ class Redis
346
358
 
347
359
  if limit
348
360
  args << "LIMIT"
349
- args.concat(limit)
361
+ args.concat(limit.map { |l| Integer(l) })
350
362
  end
351
363
 
352
364
  send_command(args)
@@ -364,7 +376,7 @@ class Redis
364
376
  #
365
377
  # @see #zrange
366
378
  def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
367
- args = [:zrevrange, key, start, stop]
379
+ args = [:zrevrange, key, Integer(start), Integer(stop)]
368
380
 
369
381
  if with_scores
370
382
  args << "WITHSCORES"
@@ -458,7 +470,7 @@ class Redis
458
470
 
459
471
  if limit
460
472
  args << "LIMIT"
461
- args.concat(limit)
473
+ args.concat(limit.map { |l| Integer(l) })
462
474
  end
463
475
 
464
476
  send_command(args)
@@ -480,7 +492,7 @@ class Redis
480
492
 
481
493
  if limit
482
494
  args << "LIMIT"
483
- args.concat(limit)
495
+ args.concat(limit.map { |l| Integer(l) })
484
496
  end
485
497
 
486
498
  send_command(args)
@@ -523,7 +535,7 @@ class Redis
523
535
 
524
536
  if limit
525
537
  args << "LIMIT"
526
- args.concat(limit)
538
+ args.concat(limit.map { |l| Integer(l) })
527
539
  end
528
540
 
529
541
  send_command(args, &block)
@@ -553,7 +565,7 @@ class Redis
553
565
 
554
566
  if limit
555
567
  args << "LIMIT"
556
- args.concat(limit)
568
+ args.concat(limit.map { |l| Integer(l) })
557
569
  end
558
570
 
559
571
  send_command(args, &block)
@@ -770,7 +782,8 @@ class Redis
770
782
  private
771
783
 
772
784
  def _zsets_operation(cmd, *keys, weights: nil, aggregate: nil, with_scores: false)
773
- command = [cmd, keys.size, *keys]
785
+ keys.flatten!(1)
786
+ command = [cmd, keys.size].concat(keys)
774
787
 
775
788
  if weights
776
789
  command << "WEIGHTS"
@@ -788,7 +801,8 @@ class Redis
788
801
  end
789
802
 
790
803
  def _zsets_operation_store(cmd, destination, keys, weights: nil, aggregate: nil)
791
- command = [cmd, destination, keys.size, *keys]
804
+ keys.flatten!(1)
805
+ command = [cmd, destination, keys.size].concat(keys)
792
806
 
793
807
  if weights
794
808
  command << "WEIGHTS"
@@ -21,15 +21,12 @@ class Redis
21
21
  # @return [Array<Hash>] information of the consumers if subcommand is `consumers`
22
22
  def xinfo(subcommand, key, group = nil)
23
23
  args = [:xinfo, subcommand, key, group].compact
24
- synchronize do |client|
25
- client.call(args) do |reply|
26
- case subcommand.to_s.downcase
27
- when 'stream' then Hashify.call(reply)
28
- when 'groups', 'consumers' then reply.map { |arr| Hashify.call(arr) }
29
- else reply
30
- end
31
- end
24
+ block = case subcommand.to_s.downcase
25
+ when 'stream' then Hashify
26
+ when 'groups', 'consumers' then proc { |r| r.map(&Hashify) }
32
27
  end
28
+
29
+ send_command(args, &block)
33
30
  end
34
31
 
35
32
  # Add new entry to the stream.
@@ -113,7 +110,7 @@ class Redis
113
110
  def xrange(key, start = '-', range_end = '+', count: nil)
114
111
  args = [:xrange, key, start, range_end]
115
112
  args.concat(['COUNT', count]) if count
116
- synchronize { |client| client.call(args, &HashifyStreamEntries) }
113
+ send_command(args, &HashifyStreamEntries)
117
114
  end
118
115
 
119
116
  # Fetches entries of the stream in descending order.
@@ -334,6 +331,8 @@ class Redis
334
331
  # redis.xpending('mystream', 'mygroup')
335
332
  # @example With range options
336
333
  # redis.xpending('mystream', 'mygroup', '-', '+', 10)
334
+ # @example With range and idle time options
335
+ # redis.xpending('mystream', 'mygroup', '-', '+', 10, idle: 9000)
337
336
  # @example With range and consumer options
338
337
  # redis.xpending('mystream', 'mygroup', '-', '+', 10, 'consumer1')
339
338
  #
@@ -344,10 +343,13 @@ class Redis
344
343
  # @param count [Integer] count the number of entries as limit
345
344
  # @param consumer [String] the consumer name
346
345
  #
346
+ # @option opts [Integer] :idle pending message minimum idle time in milliseconds
347
+ #
347
348
  # @return [Hash] the summary of pending entries
348
349
  # @return [Array<Hash>] the pending entries details if options were specified
349
- def xpending(key, group, *args)
350
+ def xpending(key, group, *args, idle: nil)
350
351
  command_args = [:xpending, key, group]
352
+ command_args << 'IDLE' << Integer(idle) if idle
351
353
  case args.size
352
354
  when 0, 3, 4
353
355
  command_args.concat(args)
@@ -25,7 +25,7 @@ class Redis
25
25
  # @param [Integer] decrement
26
26
  # @return [Integer] value after decrementing it
27
27
  def decrby(key, decrement)
28
- send_command([:decrby, key, decrement])
28
+ send_command([:decrby, key, Integer(decrement)])
29
29
  end
30
30
 
31
31
  # Increment the integer value of a key by one.
@@ -50,7 +50,7 @@ class Redis
50
50
  # @param [Integer] increment
51
51
  # @return [Integer] value after incrementing it
52
52
  def incrby(key, increment)
53
- send_command([:incrby, key, increment])
53
+ send_command([:incrby, key, Integer(increment)])
54
54
  end
55
55
 
56
56
  # Increment the numeric value of a key by the given float number.
@@ -63,7 +63,7 @@ class Redis
63
63
  # @param [Float] increment
64
64
  # @return [Float] value after incrementing it
65
65
  def incrbyfloat(key, increment)
66
- send_command([:incrbyfloat, key, increment], &Floatify)
66
+ send_command([:incrbyfloat, key, Float(increment)], &Floatify)
67
67
  end
68
68
 
69
69
  # Set the string value of a key.
@@ -82,10 +82,10 @@ class Redis
82
82
  # @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
83
83
  def set(key, value, ex: nil, px: nil, exat: nil, pxat: nil, nx: nil, xx: nil, keepttl: nil, get: nil)
84
84
  args = [:set, key, value.to_s]
85
- args << "EX" << ex if ex
86
- args << "PX" << px if px
87
- args << "EXAT" << exat if exat
88
- args << "PXAT" << pxat if pxat
85
+ args << "EX" << Integer(ex) if ex
86
+ args << "PX" << Integer(px) if px
87
+ args << "EXAT" << Integer(exat) if exat
88
+ args << "PXAT" << Integer(pxat) if pxat
89
89
  args << "NX" if nx
90
90
  args << "XX" if xx
91
91
  args << "KEEPTTL" if keepttl
@@ -105,7 +105,7 @@ class Redis
105
105
  # @param [String] value
106
106
  # @return [String] `"OK"`
107
107
  def setex(key, ttl, value)
108
- send_command([:setex, key, ttl, value.to_s])
108
+ send_command([:setex, key, Integer(ttl), value.to_s])
109
109
  end
110
110
 
111
111
  # Set the time to live in milliseconds of a key.
@@ -115,7 +115,7 @@ class Redis
115
115
  # @param [String] value
116
116
  # @return [String] `"OK"`
117
117
  def psetex(key, ttl, value)
118
- send_command([:psetex, key, ttl, value.to_s])
118
+ send_command([:psetex, key, Integer(ttl), value.to_s])
119
119
  end
120
120
 
121
121
  # Set the value of a key, only if the key does not exist.
@@ -202,6 +202,7 @@ class Redis
202
202
  #
203
203
  # @see #mapped_mget
204
204
  def mget(*keys, &blk)
205
+ keys.flatten!(1)
205
206
  send_command([:mget, *keys], &blk)
206
207
  end
207
208
 
@@ -232,7 +233,7 @@ class Redis
232
233
  # @param [String] value
233
234
  # @return [Integer] length of the string after it was modified
234
235
  def setrange(key, offset, value)
235
- send_command([:setrange, key, offset, value.to_s])
236
+ send_command([:setrange, key, Integer(offset), value.to_s])
236
237
  end
237
238
 
238
239
  # Get a substring of the string stored at a key.
@@ -243,7 +244,7 @@ class Redis
243
244
  # the end of the string
244
245
  # @return [Integer] `0` or `1`
245
246
  def getrange(key, start, stop)
246
- send_command([:getrange, key, start, stop])
247
+ send_command([:getrange, key, Integer(start), Integer(stop)])
247
248
  end
248
249
 
249
250
  # Append a value to a key.
@@ -291,10 +292,10 @@ class Redis
291
292
  # @return [String] The value of key, or nil when key does not exist.
292
293
  def getex(key, ex: nil, px: nil, exat: nil, pxat: nil, persist: false)
293
294
  args = [:getex, key]
294
- args << "EX" << ex if ex
295
- args << "PX" << px if px
296
- args << "EXAT" << exat if exat
297
- args << "PXAT" << pxat if pxat
295
+ args << "EX" << Integer(ex) if ex
296
+ args << "PX" << Integer(px) if px
297
+ args << "EXAT" << Integer(exat) if exat
298
+ args << "PXAT" << Integer(pxat) if pxat
298
299
  args << "PERSIST" if persist
299
300
 
300
301
  send_command(args)
@@ -3,6 +3,31 @@
3
3
  class Redis
4
4
  module Commands
5
5
  module Transactions
6
+ # Mark the start of a transaction block.
7
+ #
8
+ # @example With a block
9
+ # redis.multi do |multi|
10
+ # multi.set("key", "value")
11
+ # multi.incr("counter")
12
+ # end # => ["OK", 6]
13
+ #
14
+ # @yield [multi] the commands that are called inside this block are cached
15
+ # and written to the server upon returning from it
16
+ # @yieldparam [Redis] multi `self`
17
+ #
18
+ # @return [Array<...>]
19
+ # - an array with replies
20
+ #
21
+ # @see #watch
22
+ # @see #unwatch
23
+ def multi
24
+ synchronize do |client|
25
+ client.multi do |raw_transaction|
26
+ yield MultiConnection.new(raw_transaction)
27
+ end
28
+ end
29
+ end
30
+
6
31
  # Watch the given keys to determine execution of the MULTI/EXEC block.
7
32
  #
8
33
  # Using a block is optional, but is necessary for thread-safety.
@@ -35,7 +60,7 @@ class Redis
35
60
  # @see #multi
36
61
  def watch(*keys)
37
62
  synchronize do |client|
38
- res = client.call([:watch, *keys])
63
+ res = client.call_v([:watch] + keys)
39
64
 
40
65
  if block_given?
41
66
  begin
@@ -78,8 +103,6 @@ class Redis
78
103
 
79
104
  # Discard all commands issued after MULTI.
80
105
  #
81
- # Only call this method when `#multi` was called **without** a block.
82
- #
83
106
  # @return [String] `"OK"`
84
107
  #
85
108
  # @see #multi
@@ -40,14 +40,7 @@ class Redis
40
40
  # where the method call will return nil. Propagate the nil instead of falsely
41
41
  # returning false.
42
42
  Boolify = lambda { |value|
43
- case value
44
- when 1
45
- true
46
- when 0
47
- false
48
- else
49
- value
50
- end
43
+ value != 0 unless value.nil?
51
44
  }
52
45
 
53
46
  BoolifySet = lambda { |value|