redis 4.8.1 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/README.md +101 -161
  4. data/lib/redis/client.rb +82 -616
  5. data/lib/redis/commands/bitmaps.rb +14 -4
  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 +9 -6
  10. data/lib/redis/commands/hyper_log_log.rb +1 -1
  11. data/lib/redis/commands/keys.rb +21 -23
  12. data/lib/redis/commands/lists.rb +74 -25
  13. data/lib/redis/commands/pubsub.rb +28 -25
  14. data/lib/redis/commands/server.rb +15 -15
  15. data/lib/redis/commands/sets.rb +31 -40
  16. data/lib/redis/commands/sorted_sets.rb +84 -12
  17. data/lib/redis/commands/streams.rb +39 -19
  18. data/lib/redis/commands/strings.rb +18 -17
  19. data/lib/redis/commands/transactions.rb +7 -31
  20. data/lib/redis/commands.rb +4 -7
  21. data/lib/redis/distributed.rb +128 -68
  22. data/lib/redis/errors.rb +15 -50
  23. data/lib/redis/hash_ring.rb +26 -26
  24. data/lib/redis/pipeline.rb +43 -222
  25. data/lib/redis/subscribe.rb +50 -14
  26. data/lib/redis/version.rb +1 -1
  27. data/lib/redis.rb +76 -184
  28. metadata +10 -54
  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 -34
  35. data/lib/redis/cluster/option.rb +0 -100
  36. data/lib/redis/cluster/slot.rb +0 -86
  37. data/lib/redis/cluster/slot_loader.rb +0 -46
  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 -437
  43. data/lib/redis/connection/synchrony.rb +0 -148
  44. data/lib/redis/connection.rb +0 -11
@@ -15,56 +15,40 @@ class Redis
15
15
  #
16
16
  # @param [String] key
17
17
  # @param [String, Array<String>] member one member, or array of members
18
- # @return [Boolean, Integer] `Boolean` when a single member is specified,
19
- # holding whether or not adding the member succeeded, or `Integer` when an
20
- # array of members is specified, holding the number of members that were
21
- # successfully added
22
- def sadd(key, member)
23
- block = if Redis.sadd_returns_boolean && !member.is_a?(Array)
24
- ::Redis.deprecate!(
25
- "Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead." \
26
- "(called from: #{caller(1, 1).first})"
27
- )
28
- Boolify
29
- end
30
- send_command([:sadd, key, member], &block)
18
+ # @return [Integer] The number of members that were successfully added
19
+ def sadd(key, *members)
20
+ members.flatten!(1)
21
+ send_command([:sadd, key].concat(members))
31
22
  end
32
23
 
33
24
  # Add one or more members to a set.
34
25
  #
35
26
  # @param [String] key
36
27
  # @param [String, Array<String>] member one member, or array of members
37
- # @return [Boolean] Whether or not at least one member was added.
38
- def sadd?(key, member)
39
- send_command([:sadd, key, member], &Boolify)
28
+ # @return [Boolean] Wether at least one member was successfully added.
29
+ def sadd?(key, *members)
30
+ members.flatten!(1)
31
+ send_command([:sadd, key].concat(members), &Boolify)
40
32
  end
41
33
 
42
34
  # Remove one or more members from a set.
43
35
  #
44
36
  # @param [String] key
45
37
  # @param [String, Array<String>] member one member, or array of members
46
- # @return [Boolean, Integer] `Boolean` when a single member is specified,
47
- # holding whether or not removing the member succeeded, or `Integer` when an
48
- # array of members is specified, holding the number of members that were
49
- # successfully removed
50
- def srem(key, member)
51
- block = if Redis.sadd_returns_boolean && !member.is_a?(Array)
52
- ::Redis.deprecate!(
53
- "Redis#srem will always return an Integer in Redis 5.0.0. Use Redis#srem? instead." \
54
- "(called from: #{caller(1, 1).first})"
55
- )
56
- Boolify
57
- end
58
- send_command([:srem, key, member], &block)
38
+ # @return [Integer] The number of members that were successfully removed
39
+ def srem(key, *members)
40
+ members.flatten!(1)
41
+ send_command([:srem, key].concat(members))
59
42
  end
60
43
 
61
44
  # Remove one or more members from a set.
62
45
  #
63
46
  # @param [String] key
64
47
  # @param [String, Array<String>] member one member, or array of members
65
- # @return [Boolean] `Boolean` Whether or not a member was removed.
66
- def srem?(key, member)
67
- send_command([:srem, key, member], &Boolify)
48
+ # @return [Boolean] Wether at least one member was successfully removed.
49
+ def srem?(key, *members)
50
+ members.flatten!(1)
51
+ send_command([:srem, key].concat(members), &Boolify)
68
52
  end
69
53
 
70
54
  # Remove and return one or more random member from a set.
@@ -76,7 +60,7 @@ class Redis
76
60
  if count.nil?
77
61
  send_command([:spop, key])
78
62
  else
79
- send_command([:spop, key, count])
63
+ send_command([:spop, key, Integer(count)])
80
64
  end
81
65
  end
82
66
 
@@ -118,7 +102,8 @@ class Redis
118
102
  # @param [String, Array<String>] members
119
103
  # @return [Array<Boolean>]
120
104
  def smismember(key, *members)
121
- send_command([:smismember, key, *members]) do |reply|
105
+ members.flatten!(1)
106
+ send_command([:smismember, key].concat(members)) do |reply|
122
107
  reply.map(&Boolify)
123
108
  end
124
109
  end
@@ -136,7 +121,8 @@ class Redis
136
121
  # @param [String, Array<String>] keys keys pointing to sets to subtract
137
122
  # @return [Array<String>] members in the difference
138
123
  def sdiff(*keys)
139
- send_command([:sdiff, *keys])
124
+ keys.flatten!(1)
125
+ send_command([:sdiff].concat(keys))
140
126
  end
141
127
 
142
128
  # Subtract multiple sets and store the resulting set in a key.
@@ -145,7 +131,8 @@ class Redis
145
131
  # @param [String, Array<String>] keys keys pointing to sets to subtract
146
132
  # @return [Integer] number of elements in the resulting set
147
133
  def sdiffstore(destination, *keys)
148
- send_command([:sdiffstore, destination, *keys])
134
+ keys.flatten!(1)
135
+ send_command([:sdiffstore, destination].concat(keys))
149
136
  end
150
137
 
151
138
  # Intersect multiple sets.
@@ -153,7 +140,8 @@ class Redis
153
140
  # @param [String, Array<String>] keys keys pointing to sets to intersect
154
141
  # @return [Array<String>] members in the intersection
155
142
  def sinter(*keys)
156
- send_command([:sinter, *keys])
143
+ keys.flatten!(1)
144
+ send_command([:sinter].concat(keys))
157
145
  end
158
146
 
159
147
  # Intersect multiple sets and store the resulting set in a key.
@@ -162,7 +150,8 @@ class Redis
162
150
  # @param [String, Array<String>] keys keys pointing to sets to intersect
163
151
  # @return [Integer] number of elements in the resulting set
164
152
  def sinterstore(destination, *keys)
165
- send_command([:sinterstore, destination, *keys])
153
+ keys.flatten!(1)
154
+ send_command([:sinterstore, destination].concat(keys))
166
155
  end
167
156
 
168
157
  # Add multiple sets.
@@ -170,7 +159,8 @@ class Redis
170
159
  # @param [String, Array<String>] keys keys pointing to sets to unify
171
160
  # @return [Array<String>] members in the union
172
161
  def sunion(*keys)
173
- send_command([:sunion, *keys])
162
+ keys.flatten!(1)
163
+ send_command([:sunion].concat(keys))
174
164
  end
175
165
 
176
166
  # Add multiple sets and store the resulting set in a key.
@@ -179,7 +169,8 @@ class Redis
179
169
  # @param [String, Array<String>] keys keys pointing to sets to unify
180
170
  # @return [Integer] number of elements in the resulting set
181
171
  def sunionstore(destination, *keys)
182
- send_command([:sunionstore, destination, *keys])
172
+ keys.flatten!(1)
173
+ send_command([:sunionstore, destination].concat(keys))
183
174
  end
184
175
 
185
176
  # Scan a set
@@ -136,7 +136,9 @@ class Redis
136
136
  # @return [Array<String, Float>] element and score pair if count is not specified
137
137
  # @return [Array<Array<String, Float>>] list of popped elements and scores
138
138
  def zpopmax(key, count = nil)
139
- send_command([:zpopmax, key, count].compact) do |members|
139
+ command = [:zpopmax, key]
140
+ command << Integer(count) if count
141
+ send_command(command) do |members|
140
142
  members = FloatifyPairs.call(members)
141
143
  count.to_i > 1 ? members : members.first
142
144
  end
@@ -157,12 +159,80 @@ class Redis
157
159
  # @return [Array<String, Float>] element and score pair if count is not specified
158
160
  # @return [Array<Array<String, Float>>] list of popped elements and scores
159
161
  def zpopmin(key, count = nil)
160
- send_command([:zpopmin, key, count].compact) do |members|
162
+ command = [:zpopmin, key]
163
+ command << Integer(count) if count
164
+ send_command(command) do |members|
161
165
  members = FloatifyPairs.call(members)
162
166
  count.to_i > 1 ? members : members.first
163
167
  end
164
168
  end
165
169
 
170
+ # Removes and returns up to count members with scores in the sorted set stored at key.
171
+ #
172
+ # @example Popping a member
173
+ # redis.bzmpop('zset')
174
+ # #=> ['zset', ['a', 1.0]]
175
+ # @example With count option
176
+ # redis.bzmpop('zset', count: 2)
177
+ # #=> ['zset', [['a', 1.0], ['b', 2.0]]
178
+ #
179
+ # @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
180
+ # A timeout of zero can be used to block indefinitely.
181
+ # @params key [String, Array<String>] one or more keys with sorted sets
182
+ # @params modifier [String]
183
+ # - when `"MIN"` - the elements popped are those with lowest scores
184
+ # - when `"MAX"` - the elements popped are those with the highest scores
185
+ # @params count [Integer] a number of members to pop
186
+ #
187
+ # @return [Array<String, Array<String, Float>>] list of popped elements and scores
188
+ def bzmpop(timeout, *keys, modifier: "MIN", count: nil)
189
+ raise ArgumentError, "Pick either MIN or MAX" unless modifier == "MIN" || modifier == "MAX"
190
+
191
+ args = [:bzmpop, timeout, keys.size, *keys, modifier]
192
+ args << "COUNT" << Integer(count) if count
193
+
194
+ send_blocking_command(args, timeout) do |response|
195
+ response&.map do |entry|
196
+ case entry
197
+ when String then entry
198
+ when Array then entry.map { |pair| FloatifyPairs.call(pair) }.flatten(1)
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ # Removes and returns up to count members with scores in the sorted set stored at key.
205
+ #
206
+ # @example Popping a member
207
+ # redis.zmpop('zset')
208
+ # #=> ['zset', ['a', 1.0]]
209
+ # @example With count option
210
+ # redis.zmpop('zset', count: 2)
211
+ # #=> ['zset', [['a', 1.0], ['b', 2.0]]
212
+ #
213
+ # @params key [String, Array<String>] one or more keys with sorted sets
214
+ # @params modifier [String]
215
+ # - when `"MIN"` - the elements popped are those with lowest scores
216
+ # - when `"MAX"` - the elements popped are those with the highest scores
217
+ # @params count [Integer] a number of members to pop
218
+ #
219
+ # @return [Array<String, Array<String, Float>>] list of popped elements and scores
220
+ def zmpop(*keys, modifier: "MIN", count: nil)
221
+ raise ArgumentError, "Pick either MIN or MAX" unless modifier == "MIN" || modifier == "MAX"
222
+
223
+ args = [:zmpop, keys.size, *keys, modifier]
224
+ args << "COUNT" << Integer(count) if count
225
+
226
+ send_command(args) do |response|
227
+ response&.map do |entry|
228
+ case entry
229
+ when String then entry
230
+ when Array then entry.map { |pair| FloatifyPairs.call(pair) }.flatten(1)
231
+ end
232
+ end
233
+ end
234
+ end
235
+
166
236
  # Removes and returns up to count members with the highest scores in the sorted set stored at keys,
167
237
  # or block until one is available.
168
238
  #
@@ -261,7 +331,7 @@ class Redis
261
331
  end
262
332
 
263
333
  args = [:zrandmember, key]
264
- args << count if count
334
+ args << Integer(count) if count
265
335
 
266
336
  if with_scores
267
337
  args << "WITHSCORES"
@@ -313,7 +383,7 @@ class Redis
313
383
 
314
384
  if limit
315
385
  args << "LIMIT"
316
- args.concat(limit)
386
+ args.concat(limit.map { |l| Integer(l) })
317
387
  end
318
388
 
319
389
  if with_scores
@@ -354,7 +424,7 @@ class Redis
354
424
 
355
425
  if limit
356
426
  args << "LIMIT"
357
- args.concat(limit)
427
+ args.concat(limit.map { |l| Integer(l) })
358
428
  end
359
429
 
360
430
  send_command(args)
@@ -372,7 +442,7 @@ class Redis
372
442
  #
373
443
  # @see #zrange
374
444
  def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
375
- args = [:zrevrange, key, start, stop]
445
+ args = [:zrevrange, key, Integer(start), Integer(stop)]
376
446
 
377
447
  if with_scores
378
448
  args << "WITHSCORES"
@@ -466,7 +536,7 @@ class Redis
466
536
 
467
537
  if limit
468
538
  args << "LIMIT"
469
- args.concat(limit)
539
+ args.concat(limit.map { |l| Integer(l) })
470
540
  end
471
541
 
472
542
  send_command(args)
@@ -488,7 +558,7 @@ class Redis
488
558
 
489
559
  if limit
490
560
  args << "LIMIT"
491
- args.concat(limit)
561
+ args.concat(limit.map { |l| Integer(l) })
492
562
  end
493
563
 
494
564
  send_command(args)
@@ -531,7 +601,7 @@ class Redis
531
601
 
532
602
  if limit
533
603
  args << "LIMIT"
534
- args.concat(limit)
604
+ args.concat(limit.map { |l| Integer(l) })
535
605
  end
536
606
 
537
607
  send_command(args, &block)
@@ -561,7 +631,7 @@ class Redis
561
631
 
562
632
  if limit
563
633
  args << "LIMIT"
564
- args.concat(limit)
634
+ args.concat(limit.map { |l| Integer(l) })
565
635
  end
566
636
 
567
637
  send_command(args, &block)
@@ -778,7 +848,8 @@ class Redis
778
848
  private
779
849
 
780
850
  def _zsets_operation(cmd, *keys, weights: nil, aggregate: nil, with_scores: false)
781
- command = [cmd, keys.size, *keys]
851
+ keys.flatten!(1)
852
+ command = [cmd, keys.size].concat(keys)
782
853
 
783
854
  if weights
784
855
  command << "WEIGHTS"
@@ -796,7 +867,8 @@ class Redis
796
867
  end
797
868
 
798
869
  def _zsets_operation_store(cmd, destination, keys, weights: nil, aggregate: nil)
799
- command = [cmd, destination, keys.size, *keys]
870
+ keys.flatten!(1)
871
+ command = [cmd, destination, keys.size].concat(keys)
800
872
 
801
873
  if weights
802
874
  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.
@@ -37,7 +34,7 @@ class Redis
37
34
  # @example Without options
38
35
  # redis.xadd('mystream', f1: 'v1', f2: 'v2')
39
36
  # @example With options
40
- # redis.xadd('mystream', { f1: 'v1', f2: 'v2' }, id: '0-0', maxlen: 1000, approximate: true)
37
+ # redis.xadd('mystream', { f1: 'v1', f2: 'v2' }, id: '0-0', maxlen: 1000, approximate: true, nomkstream: true)
41
38
  #
42
39
  # @param key [String] the stream key
43
40
  # @param entry [Hash] one or multiple field-value pairs
@@ -46,17 +43,19 @@ class Redis
46
43
  # @option opts [String] :id the entry id, default value is `*`, it means auto generation
47
44
  # @option opts [Integer] :maxlen max length of entries
48
45
  # @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
46
+ # @option opts [Boolean] :nomkstream whether to add NOMKSTREAM, default is not to add
49
47
  #
50
48
  # @return [String] the entry id
51
- def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
49
+ def xadd(key, entry, approximate: nil, maxlen: nil, nomkstream: nil, id: '*')
52
50
  args = [:xadd, key]
51
+ args << 'NOMKSTREAM' if nomkstream
53
52
  if maxlen
54
53
  args << "MAXLEN"
55
54
  args << "~" if approximate
56
55
  args << maxlen
57
56
  end
58
57
  args << id
59
- args.concat(entry.to_a.flatten)
58
+ args.concat(entry.flatten)
60
59
  send_command(args)
61
60
  end
62
61
 
@@ -66,14 +65,30 @@ class Redis
66
65
  # redis.xtrim('mystream', 1000)
67
66
  # @example With options
68
67
  # redis.xtrim('mystream', 1000, approximate: true)
69
- #
70
- # @param key [String] the stream key
71
- # @param mexlen [Integer] max length of entries
72
- # @param approximate [Boolean] whether to add `~` modifier of maxlen or not
68
+ # @example With strategy
69
+ # redis.xtrim('mystream', '1-0', strategy: 'MINID')
70
+ #
71
+ # @overload xtrim(key, maxlen, strategy: 'MAXLEN', approximate: true)
72
+ # @param key [String] the stream key
73
+ # @param maxlen [Integer] max length of entries
74
+ # @param strategy [String] the limit strategy, must be MAXLEN
75
+ # @param approximate [Boolean] whether to add `~` modifier of maxlen or not
76
+ # @param limit [Integer] maximum count of entries to be evicted
77
+ # @overload xtrim(key, minid, strategy: 'MINID', approximate: true)
78
+ # @param key [String] the stream key
79
+ # @param minid [String] minimum id of entries
80
+ # @param strategy [String] the limit strategy, must be MINID
81
+ # @param approximate [Boolean] whether to add `~` modifier of minid or not
82
+ # @param limit [Integer] maximum count of entries to be evicted
73
83
  #
74
84
  # @return [Integer] the number of entries actually deleted
75
- def xtrim(key, maxlen, approximate: false)
76
- args = [:xtrim, key, 'MAXLEN', (approximate ? '~' : nil), maxlen].compact
85
+ def xtrim(key, len_or_id, strategy: 'MAXLEN', approximate: false, limit: nil)
86
+ strategy = strategy.to_s.upcase
87
+
88
+ args = [:xtrim, key, strategy]
89
+ args << '~' if approximate
90
+ args << len_or_id
91
+ args.concat(['LIMIT', limit]) if limit
77
92
  send_command(args)
78
93
  end
79
94
 
@@ -113,7 +128,7 @@ class Redis
113
128
  def xrange(key, start = '-', range_end = '+', count: nil)
114
129
  args = [:xrange, key, start, range_end]
115
130
  args.concat(['COUNT', count]) if count
116
- synchronize { |client| client.call(args, &HashifyStreamEntries) }
131
+ send_command(args, &HashifyStreamEntries)
117
132
  end
118
133
 
119
134
  # Fetches entries of the stream in descending order.
@@ -334,6 +349,8 @@ class Redis
334
349
  # redis.xpending('mystream', 'mygroup')
335
350
  # @example With range options
336
351
  # redis.xpending('mystream', 'mygroup', '-', '+', 10)
352
+ # @example With range and idle time options
353
+ # redis.xpending('mystream', 'mygroup', '-', '+', 10, idle: 9000)
337
354
  # @example With range and consumer options
338
355
  # redis.xpending('mystream', 'mygroup', '-', '+', 10, 'consumer1')
339
356
  #
@@ -344,10 +361,13 @@ class Redis
344
361
  # @param count [Integer] count the number of entries as limit
345
362
  # @param consumer [String] the consumer name
346
363
  #
364
+ # @option opts [Integer] :idle pending message minimum idle time in milliseconds
365
+ #
347
366
  # @return [Hash] the summary of pending entries
348
367
  # @return [Array<Hash>] the pending entries details if options were specified
349
- def xpending(key, group, *args)
368
+ def xpending(key, group, *args, idle: nil)
350
369
  command_args = [:xpending, key, group]
370
+ command_args << 'IDLE' << Integer(idle) if idle
351
371
  case args.size
352
372
  when 0, 3, 4
353
373
  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.
@@ -152,7 +152,7 @@ class Redis
152
152
  #
153
153
  # @see #mset
154
154
  def mapped_mset(hash)
155
- mset(hash.to_a.flatten)
155
+ mset(hash.flatten)
156
156
  end
157
157
 
158
158
  # Set one or more values, only if none of the keys exist.
@@ -180,7 +180,7 @@ class Redis
180
180
  #
181
181
  # @see #msetnx
182
182
  def mapped_msetnx(hash)
183
- msetnx(hash.to_a.flatten)
183
+ msetnx(hash.flatten)
184
184
  end
185
185
 
186
186
  # Get the value of a key.
@@ -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)
@@ -5,48 +5,26 @@ class Redis
5
5
  module Transactions
6
6
  # Mark the start of a transaction block.
7
7
  #
8
- # Passing a block is optional.
9
- #
10
8
  # @example With a block
11
9
  # redis.multi do |multi|
12
10
  # multi.set("key", "value")
13
11
  # multi.incr("counter")
14
12
  # end # => ["OK", 6]
15
13
  #
16
- # @example Without a block
17
- # redis.multi
18
- # # => "OK"
19
- # redis.set("key", "value")
20
- # # => "QUEUED"
21
- # redis.incr("counter")
22
- # # => "QUEUED"
23
- # redis.exec
24
- # # => ["OK", 6]
25
- #
26
14
  # @yield [multi] the commands that are called inside this block are cached
27
15
  # and written to the server upon returning from it
28
16
  # @yieldparam [Redis] multi `self`
29
17
  #
30
- # @return [String, Array<...>]
31
- # - when a block is not given, `OK`
32
- # - when a block is given, an array with replies
18
+ # @return [Array<...>]
19
+ # - an array with replies
33
20
  #
34
21
  # @see #watch
35
22
  # @see #unwatch
36
- def multi(&block) # :nodoc:
37
- if block_given?
38
- if block&.arity == 0
39
- Pipeline.deprecation_warning("multi", Kernel.caller_locations(1, 5))
40
- end
41
-
42
- synchronize do |prior_client|
43
- pipeline = Pipeline::Multi.new(prior_client)
44
- pipelined_connection = PipelinedConnection.new(pipeline)
45
- yield pipelined_connection
46
- prior_client.call_pipeline(pipeline)
23
+ def multi
24
+ synchronize do |client|
25
+ client.multi do |raw_transaction|
26
+ yield MultiConnection.new(raw_transaction)
47
27
  end
48
- else
49
- send_command([:multi])
50
28
  end
51
29
  end
52
30
 
@@ -82,7 +60,7 @@ class Redis
82
60
  # @see #multi
83
61
  def watch(*keys)
84
62
  synchronize do |client|
85
- res = client.call([:watch, *keys])
63
+ res = client.call_v([:watch] + keys)
86
64
 
87
65
  if block_given?
88
66
  begin
@@ -125,8 +103,6 @@ class Redis
125
103
 
126
104
  # Discard all commands issued after MULTI.
127
105
  #
128
- # Only call this method when `#multi` was called **without** a block.
129
- #
130
106
  # @return [String] `"OK"`
131
107
  #
132
108
  # @see #multi
@@ -40,12 +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 Integer
45
- value > 0
46
- else
47
- value
48
- end
43
+ value != 0 unless value.nil?
49
44
  }
50
45
 
51
46
  BoolifySet = lambda { |value|
@@ -124,7 +119,9 @@ class Redis
124
119
  HashifyStreamAutoclaim = lambda { |reply|
125
120
  {
126
121
  'next' => reply[0],
127
- 'entries' => reply[1].map { |entry| [entry[0], entry[1].each_slice(2).to_h] }
122
+ 'entries' => reply[1].compact.map do |entry, values|
123
+ [entry, values.each_slice(2)&.to_h]
124
+ end
128
125
  }
129
126
  }
130
127