redis 4.8.0 → 5.0.2

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 +31 -0
  3. data/README.md +75 -161
  4. data/lib/redis/client.rb +81 -613
  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 +1 -19
  12. data/lib/redis/commands/lists.rb +20 -25
  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 +31 -40
  16. data/lib/redis/commands/sorted_sets.rb +18 -12
  17. data/lib/redis/commands/streams.rb +12 -10
  18. data/lib/redis/commands/strings.rb +14 -13
  19. data/lib/redis/commands/transactions.rb +7 -31
  20. data/lib/redis/commands.rb +1 -6
  21. data/lib/redis/distributed.rb +86 -64
  22. data/lib/redis/errors.rb +11 -50
  23. data/lib/redis/hash_ring.rb +26 -26
  24. data/lib/redis/pipeline.rb +43 -222
  25. data/lib/redis/subscribe.rb +23 -15
  26. data/lib/redis/version.rb +1 -1
  27. data/lib/redis.rb +89 -184
  28. metadata +11 -55
  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
@@ -39,7 +39,10 @@ class Redis
39
39
  # @param [String, Array<String>] keys one or more source keys to perform `operation`
40
40
  # @return [Integer] the length of the string stored in `destkey`
41
41
  def bitop(operation, destkey, *keys)
42
- send_command([:bitop, operation, destkey, *keys])
42
+ keys.flatten!(1)
43
+ command = [:bitop, operation, destkey]
44
+ command.concat(keys)
45
+ send_command(command)
43
46
  end
44
47
 
45
48
  # Return the position of the first bit set to 1 or 0 in a string.
@@ -12,24 +12,7 @@ class Redis
12
12
  #
13
13
  # @return [Object] depends on the subcommand
14
14
  def cluster(subcommand, *args)
15
- subcommand = subcommand.to_s.downcase
16
- block = case subcommand
17
- when 'slots'
18
- HashifyClusterSlots
19
- when 'nodes'
20
- HashifyClusterNodes
21
- when 'slaves'
22
- HashifyClusterSlaves
23
- when 'info'
24
- HashifyInfo
25
- else
26
- Noop
27
- end
28
-
29
- # @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
30
- block = Noop unless @cluster_mode
31
-
32
- send_command([:cluster, subcommand] + args, &block)
15
+ send_command([:cluster, subcommand] + args)
33
16
  end
34
17
 
35
18
  # Sends `ASKING` command to random node and returns its reply.
@@ -34,10 +34,7 @@ class Redis
34
34
  # @param [Integer] db zero-based index of the DB to use (0 to 15)
35
35
  # @return [String] `OK`
36
36
  def select(db)
37
- synchronize do |client|
38
- client.db = db
39
- client.call([:select, db])
40
- end
37
+ send_command([:select, db])
41
38
  end
42
39
 
43
40
  # Close the connection.
@@ -45,12 +42,10 @@ class Redis
45
42
  # @return [String] `OK`
46
43
  def quit
47
44
  synchronize do |client|
48
- begin
49
- client.call([:quit])
50
- rescue ConnectionError
51
- ensure
52
- client.disconnect
53
- end
45
+ client.call_v([:quit])
46
+ rescue ConnectionError
47
+ ensure
48
+ client.close
54
49
  end
55
50
  end
56
51
  end
@@ -74,9 +74,9 @@ class Redis
74
74
  private
75
75
 
76
76
  def _geoarguments(*args, options: nil, sort: nil, count: nil)
77
- args.push sort if sort
78
- args.push 'count', count if count
79
- args.push options if options
77
+ args << sort if sort
78
+ args << 'COUNT' << Integer(count) if count
79
+ args << options if options
80
80
  args
81
81
  end
82
82
  end
@@ -87,7 +87,8 @@ class Redis
87
87
  #
88
88
  # @see #mapped_hmget
89
89
  def hmget(key, *fields, &blk)
90
- send_command([:hmget, key] + fields, &blk)
90
+ fields.flatten!(1)
91
+ send_command([:hmget, key].concat(fields), &blk)
91
92
  end
92
93
 
93
94
  # Get the values of all the given hash fields.
@@ -102,7 +103,8 @@ class Redis
102
103
  #
103
104
  # @see #hmget
104
105
  def mapped_hmget(key, *fields)
105
- hmget(key, *fields) do |reply|
106
+ fields.flatten!(1)
107
+ hmget(key, fields) do |reply|
106
108
  if reply.is_a?(Array)
107
109
  Hash[fields.zip(reply)]
108
110
  else
@@ -152,7 +154,8 @@ class Redis
152
154
  # @param [String, Array<String>] field
153
155
  # @return [Integer] the number of fields that were removed from the hash
154
156
  def hdel(key, *fields)
155
- send_command([:hdel, key, *fields])
157
+ fields.flatten!(1)
158
+ send_command([:hdel, key].concat(fields))
156
159
  end
157
160
 
158
161
  # Determine if a hash field exists.
@@ -171,7 +174,7 @@ class Redis
171
174
  # @param [Integer] increment
172
175
  # @return [Integer] value of the field after incrementing it
173
176
  def hincrby(key, field, increment)
174
- send_command([:hincrby, key, field, increment])
177
+ send_command([:hincrby, key, field, Integer(increment)])
175
178
  end
176
179
 
177
180
  # Increment the numeric value of a hash field by the given float number.
@@ -181,7 +184,7 @@ class Redis
181
184
  # @param [Float] increment
182
185
  # @return [Float] value of the field after incrementing it
183
186
  def hincrbyfloat(key, field, increment)
184
- send_command([:hincrbyfloat, key, field, increment], &Floatify)
187
+ send_command([:hincrbyfloat, key, field, Float(increment)], &Floatify)
185
188
  end
186
189
 
187
190
  # Get all the fields in a hash.
@@ -20,7 +20,7 @@ class Redis
20
20
  # @param [String, Array<String>] keys
21
21
  # @return [Integer]
22
22
  def pfcount(*keys)
23
- send_command([:pfcount] + keys)
23
+ send_command([:pfcount] + keys.flatten(1))
24
24
  end
25
25
 
26
26
  # Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
@@ -249,24 +249,6 @@ class Redis
249
249
  # @param [String, Array<String>] keys
250
250
  # @return [Integer]
251
251
  def exists(*keys)
252
- if !Redis.exists_returns_integer && keys.size == 1
253
- if Redis.exists_returns_integer.nil?
254
- message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
255
- "should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
256
- "true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
257
- "`Redis.exists_returns_integer = false`, but this option will be removed in 5.0.0. " \
258
- "(#{::Kernel.caller(1, 1).first})\n"
259
-
260
- ::Redis.deprecate!(message)
261
- end
262
-
263
- exists?(*keys)
264
- else
265
- _exists(*keys)
266
- end
267
- end
268
-
269
- def _exists(*keys)
270
252
  send_command([:exists, *keys])
271
253
  end
272
254
 
@@ -445,7 +427,7 @@ class Redis
445
427
 
446
428
  args << cursor
447
429
  args << "MATCH" << match if match
448
- args << "COUNT" << count if count
430
+ args << "COUNT" << Integer(count) if count
449
431
  args << "TYPE" << type if type
450
432
 
451
433
  send_command([command] + args, &block)
@@ -48,7 +48,7 @@ class Redis
48
48
  # @param [String, Symbol] where_destination where to push the element to the source list
49
49
  # e.g. 'LEFT' - to head, 'RIGHT' - to tail
50
50
  # @param [Hash] options
51
- # - `:timeout => Numeric`: timeout in seconds, defaults to no timeout
51
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
52
52
  #
53
53
  # @return [nil, String] the element, or nil when the source key does not exist or the timeout expired
54
54
  #
@@ -99,10 +99,10 @@ class Redis
99
99
  #
100
100
  # @param [String] key
101
101
  # @param [Integer] count number of elements to remove
102
- # @return [String, Array<String>] the values of the first elements
102
+ # @return [nil, String, Array<String>] the values of the first elements
103
103
  def lpop(key, count = nil)
104
104
  command = [:lpop, key]
105
- command << count if count
105
+ command << Integer(count) if count
106
106
  send_command(command)
107
107
  end
108
108
 
@@ -110,10 +110,10 @@ class Redis
110
110
  #
111
111
  # @param [String] key
112
112
  # @param [Integer] count number of elements to remove
113
- # @return [String, Array<String>] the values of the last elements
113
+ # @return [nil, String, Array<String>] the values of the last elements
114
114
  def rpop(key, count = nil)
115
115
  command = [:rpop, key]
116
- command << count if count
116
+ command << Integer(count) if count
117
117
  send_command(command)
118
118
  end
119
119
 
@@ -142,7 +142,7 @@ class Redis
142
142
  # @param [String, Array<String>] keys one or more keys to perform the
143
143
  # blocking pop on
144
144
  # @param [Hash] options
145
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
145
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
146
146
  #
147
147
  # @return [nil, [String, String]]
148
148
  # - `nil` when the operation timed out
@@ -156,7 +156,7 @@ class Redis
156
156
  # @param [String, Array<String>] keys one or more keys to perform the
157
157
  # blocking pop on
158
158
  # @param [Hash] options
159
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
159
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
160
160
  #
161
161
  # @return [nil, [String, String]]
162
162
  # - `nil` when the operation timed out
@@ -173,12 +173,12 @@ class Redis
173
173
  # @param [String] source source key
174
174
  # @param [String] destination destination key
175
175
  # @param [Hash] options
176
- # - `:timeout => Integer`: timeout in seconds, defaults to no timeout
176
+ # - `:timeout => [Float, Integer]`: timeout in seconds, defaults to no timeout
177
177
  #
178
178
  # @return [nil, String]
179
179
  # - `nil` when the operation timed out
180
180
  # - the element was popped and pushed otherwise
181
- def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
181
+ def brpoplpush(source, destination, timeout: 0)
182
182
  command = [:brpoplpush, source, destination, timeout]
183
183
  send_blocking_command(command, timeout)
184
184
  end
@@ -189,7 +189,7 @@ class Redis
189
189
  # @param [Integer] index
190
190
  # @return [String]
191
191
  def lindex(key, index)
192
- send_command([:lindex, key, index])
192
+ send_command([:lindex, key, Integer(index)])
193
193
  end
194
194
 
195
195
  # Insert an element before or after another element in a list.
@@ -211,7 +211,7 @@ class Redis
211
211
  # @param [Integer] stop stop index
212
212
  # @return [Array<String>]
213
213
  def lrange(key, start, stop)
214
- send_command([:lrange, key, start, stop])
214
+ send_command([:lrange, key, Integer(start), Integer(stop)])
215
215
  end
216
216
 
217
217
  # Remove elements from a list.
@@ -224,7 +224,7 @@ class Redis
224
224
  # @param [String] value
225
225
  # @return [Integer] the number of removed elements
226
226
  def lrem(key, count, value)
227
- send_command([:lrem, key, count, value])
227
+ send_command([:lrem, key, Integer(count), value])
228
228
  end
229
229
 
230
230
  # Set the value of an element in a list by its index.
@@ -234,7 +234,7 @@ class Redis
234
234
  # @param [String] value
235
235
  # @return [String] `OK`
236
236
  def lset(key, index, value)
237
- send_command([:lset, key, index, value])
237
+ send_command([:lset, key, Integer(index), value])
238
238
  end
239
239
 
240
240
  # Trim a list to the specified range.
@@ -244,7 +244,7 @@ class Redis
244
244
  # @param [Integer] stop stop index
245
245
  # @return [String] `OK`
246
246
  def ltrim(key, start, stop)
247
- send_command([:ltrim, key, start, stop])
247
+ send_command([:ltrim, key, Integer(start), Integer(stop)])
248
248
  end
249
249
 
250
250
  private
@@ -253,21 +253,16 @@ class Redis
253
253
  timeout = if args.last.is_a?(Hash)
254
254
  options = args.pop
255
255
  options[:timeout]
256
- elsif args.last.respond_to?(:to_int)
257
- last_arg = args.pop
258
- ::Redis.deprecate!(
259
- "Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
260
- " redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
261
- "(called from: #{caller(2, 1).first})"
262
- )
263
- last_arg.to_int
264
256
  end
265
257
 
266
258
  timeout ||= 0
259
+ unless timeout.is_a?(Integer) || timeout.is_a?(Float)
260
+ raise ArgumentError, "timeout must be an Integer or Float, got: #{timeout.class}"
261
+ end
267
262
 
268
- keys = args.flatten
269
-
270
- command = [cmd, keys, timeout]
263
+ args.flatten!(1)
264
+ command = [cmd].concat(args)
265
+ command << timeout
271
266
  send_blocking_command(command, timeout, &blk)
272
267
  end
273
268
 
@@ -9,57 +9,39 @@ class Redis
9
9
  end
10
10
 
11
11
  def subscribed?
12
- synchronize do |client|
13
- client.is_a? SubscribedClient
14
- end
12
+ !@subscription_client.nil?
15
13
  end
16
14
 
17
15
  # Listen for messages published to the given channels.
18
16
  def subscribe(*channels, &block)
19
- synchronize do |_client|
20
- _subscription(:subscribe, 0, channels, block)
21
- end
17
+ _subscription(:subscribe, 0, channels, block)
22
18
  end
23
19
 
24
20
  # Listen for messages published to the given channels. Throw a timeout error
25
21
  # if there is no messages for a timeout period.
26
22
  def subscribe_with_timeout(timeout, *channels, &block)
27
- synchronize do |_client|
28
- _subscription(:subscribe_with_timeout, timeout, channels, block)
29
- end
23
+ _subscription(:subscribe_with_timeout, timeout, channels, block)
30
24
  end
31
25
 
32
26
  # Stop listening for messages posted to the given channels.
33
27
  def unsubscribe(*channels)
34
- synchronize do |client|
35
- raise "Can't unsubscribe if not subscribed." unless subscribed?
36
-
37
- client.unsubscribe(*channels)
38
- end
28
+ _subscription(:unsubscribe, 0, channels, nil)
39
29
  end
40
30
 
41
31
  # Listen for messages published to channels matching the given patterns.
42
32
  def psubscribe(*channels, &block)
43
- synchronize do |_client|
44
- _subscription(:psubscribe, 0, channels, block)
45
- end
33
+ _subscription(:psubscribe, 0, channels, block)
46
34
  end
47
35
 
48
36
  # Listen for messages published to channels matching the given patterns.
49
37
  # Throw a timeout error if there is no messages for a timeout period.
50
38
  def psubscribe_with_timeout(timeout, *channels, &block)
51
- synchronize do |_client|
52
- _subscription(:psubscribe_with_timeout, timeout, channels, block)
53
- end
39
+ _subscription(:psubscribe_with_timeout, timeout, channels, block)
54
40
  end
55
41
 
56
42
  # Stop listening for messages posted to channels matching the given patterns.
57
43
  def punsubscribe(*channels)
58
- synchronize do |client|
59
- raise "Can't unsubscribe if not subscribed." unless subscribed?
60
-
61
- client.punsubscribe(*channels)
62
- end
44
+ _subscription(:punsubscribe, 0, channels, nil)
63
45
  end
64
46
 
65
47
  # Inspect the state of the Pub/Sub subsystem.
@@ -36,7 +36,7 @@ class Redis
36
36
  #
37
37
  # @param [String, Symbol] subcommand e.g. `kill`, `list`, `getname`, `setname`
38
38
  # @return [String, Hash] depends on subcommand
39
- def client(subcommand = nil, *args)
39
+ def client(subcommand, *args)
40
40
  send_command([:client, subcommand] + args) do |reply|
41
41
  if subcommand.to_s == "list"
42
42
  reply.lines.map do |line|
@@ -117,9 +117,13 @@ class Redis
117
117
  #
118
118
  # @yield a block to be called for every line of output
119
119
  # @yieldparam [String] line timestamp and command that was executed
120
- def monitor(&block)
120
+ def monitor
121
121
  synchronize do |client|
122
- client.call_loop([:monitor], &block)
122
+ client = client.pubsub
123
+ client.call_v([:monitor])
124
+ loop do
125
+ yield client.next_event
126
+ end
123
127
  end
124
128
  end
125
129
 
@@ -133,13 +137,11 @@ class Redis
133
137
  # Synchronously save the dataset to disk and then shut down the server.
134
138
  def shutdown
135
139
  synchronize do |client|
136
- client.with_reconnect(false) do
137
- begin
138
- client.call([:shutdown])
139
- rescue ConnectionError
140
- # This means Redis has probably exited.
141
- nil
142
- end
140
+ client.disable_reconnection do
141
+ client.call_v([:shutdown])
142
+ rescue ConnectionError
143
+ # This means Redis has probably exited.
144
+ nil
143
145
  end
144
146
  end
145
147
  end
@@ -155,11 +157,9 @@ class Redis
155
157
  # @param [Integer] length maximum number of entries to return
156
158
  # @return [Array<String>, Integer, String] depends on subcommand
157
159
  def slowlog(subcommand, length = nil)
158
- synchronize do |client|
159
- args = [:slowlog, subcommand]
160
- args << length if length
161
- client.call args
162
- end
160
+ args = [:slowlog, subcommand]
161
+ args << Integer(length) if length
162
+ send_command(args)
163
163
  end
164
164
 
165
165
  # Internal command used for replication.
@@ -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#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? 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