redis 4.8.1 → 5.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -0
- data/README.md +125 -162
- data/lib/redis/client.rb +82 -616
- data/lib/redis/commands/bitmaps.rb +14 -4
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +3 -3
- data/lib/redis/commands/hashes.rb +13 -6
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +27 -23
- data/lib/redis/commands/lists.rb +74 -25
- data/lib/redis/commands/pubsub.rb +34 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +35 -40
- data/lib/redis/commands/sorted_sets.rb +128 -18
- data/lib/redis/commands/streams.rb +48 -21
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +11 -12
- data/lib/redis/distributed.rb +136 -72
- data/lib/redis/errors.rb +15 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +47 -222
- data/lib/redis/subscribe.rb +50 -14
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +77 -184
- metadata +10 -57
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
@@ -27,9 +27,13 @@ class Redis
|
|
27
27
|
# @param [String] key
|
28
28
|
# @param [Integer] start start index
|
29
29
|
# @param [Integer] stop stop index
|
30
|
+
# @param [String, Symbol] scale the scale of the offset range
|
31
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
30
32
|
# @return [Integer] the number of bits set to 1
|
31
|
-
def bitcount(key, start = 0, stop = -1)
|
32
|
-
|
33
|
+
def bitcount(key, start = 0, stop = -1, scale: nil)
|
34
|
+
command = [:bitcount, key, start, stop]
|
35
|
+
command << scale if scale
|
36
|
+
send_command(command)
|
33
37
|
end
|
34
38
|
|
35
39
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
@@ -39,7 +43,10 @@ class Redis
|
|
39
43
|
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
40
44
|
# @return [Integer] the length of the string stored in `destkey`
|
41
45
|
def bitop(operation, destkey, *keys)
|
42
|
-
|
46
|
+
keys.flatten!(1)
|
47
|
+
command = [:bitop, operation, destkey]
|
48
|
+
command.concat(keys)
|
49
|
+
send_command(command)
|
43
50
|
end
|
44
51
|
|
45
52
|
# Return the position of the first bit set to 1 or 0 in a string.
|
@@ -48,14 +55,17 @@ class Redis
|
|
48
55
|
# @param [Integer] bit whether to look for the first 1 or 0 bit
|
49
56
|
# @param [Integer] start start index
|
50
57
|
# @param [Integer] stop stop index
|
58
|
+
# @param [String, Symbol] scale the scale of the offset range
|
59
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
51
60
|
# @return [Integer] the position of the first 1/0 bit.
|
52
61
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
53
|
-
def bitpos(key, bit, start = nil, stop = nil)
|
62
|
+
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
|
54
63
|
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
55
64
|
|
56
65
|
command = [:bitpos, key, bit]
|
57
66
|
command << start if start
|
58
67
|
command << stop if stop
|
68
|
+
command << scale if scale
|
59
69
|
send_command(command)
|
60
70
|
end
|
61
71
|
end
|
@@ -12,24 +12,7 @@ class Redis
|
|
12
12
|
#
|
13
13
|
# @return [Object] depends on the subcommand
|
14
14
|
def cluster(subcommand, *args)
|
15
|
-
subcommand
|
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
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
data/lib/redis/commands/geo.rb
CHANGED
@@ -74,9 +74,9 @@ class Redis
|
|
74
74
|
private
|
75
75
|
|
76
76
|
def _geoarguments(*args, options: nil, sort: nil, count: nil)
|
77
|
-
args
|
78
|
-
args
|
79
|
-
args
|
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
|
@@ -63,7 +63,7 @@ class Redis
|
|
63
63
|
#
|
64
64
|
# @see #hmset
|
65
65
|
def mapped_hmset(key, hash)
|
66
|
-
hmset(key, hash.
|
66
|
+
hmset(key, hash.flatten)
|
67
67
|
end
|
68
68
|
|
69
69
|
# Get the value of a hash field.
|
@@ -87,7 +87,8 @@ class Redis
|
|
87
87
|
#
|
88
88
|
# @see #mapped_hmget
|
89
89
|
def hmget(key, *fields, &blk)
|
90
|
-
|
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
|
-
|
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
|
-
|
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.
|
@@ -219,6 +222,8 @@ class Redis
|
|
219
222
|
# - `:count => Integer`: return count keys at most per iteration
|
220
223
|
#
|
221
224
|
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
225
|
+
#
|
226
|
+
# See the [Redis Server HSCAN documentation](https://redis.io/docs/latest/commands/hscan/) for further details
|
222
227
|
def hscan(key, cursor, **options)
|
223
228
|
_scan(:hscan, cursor, [key], **options) do |reply|
|
224
229
|
[reply[0], reply[1].each_slice(2).to_a]
|
@@ -236,6 +241,8 @@ class Redis
|
|
236
241
|
# - `:count => Integer`: return count keys at most per iteration
|
237
242
|
#
|
238
243
|
# @return [Enumerator] an enumerator for all found keys
|
244
|
+
#
|
245
|
+
# See the [Redis Server HSCAN documentation](https://redis.io/docs/latest/commands/hscan/) for further details
|
239
246
|
def hscan_each(key, **options, &block)
|
240
247
|
return to_enum(:hscan_each, key, **options) unless block_given?
|
241
248
|
|
@@ -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
|
data/lib/redis/commands/keys.rb
CHANGED
@@ -22,6 +22,8 @@ class Redis
|
|
22
22
|
# - `:type => String`: return keys only of the given type
|
23
23
|
#
|
24
24
|
# @return [String, Array<String>] the next cursor and all found keys
|
25
|
+
#
|
26
|
+
# See the [Redis Server SCAN documentation](https://redis.io/docs/latest/commands/scan/) for further details
|
25
27
|
def scan(cursor, **options)
|
26
28
|
_scan(:scan, cursor, [], **options)
|
27
29
|
end
|
@@ -46,6 +48,8 @@ class Redis
|
|
46
48
|
# - `:type => String`: return keys only of the given type
|
47
49
|
#
|
48
50
|
# @return [Enumerator] an enumerator for all found keys
|
51
|
+
#
|
52
|
+
# See the [Redis Server SCAN documentation](https://redis.io/docs/latest/commands/scan/) for further details
|
49
53
|
def scan_each(**options, &block)
|
50
54
|
return to_enum(:scan_each, **options) unless block_given?
|
51
55
|
|
@@ -76,7 +80,7 @@ class Redis
|
|
76
80
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
77
81
|
# @return [Boolean] whether the timeout was set or not
|
78
82
|
def expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil)
|
79
|
-
args = [:expire, key, seconds]
|
83
|
+
args = [:expire, key, Integer(seconds)]
|
80
84
|
args << "NX" if nx
|
81
85
|
args << "XX" if xx
|
82
86
|
args << "GT" if gt
|
@@ -96,7 +100,7 @@ class Redis
|
|
96
100
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
97
101
|
# @return [Boolean] whether the timeout was set or not
|
98
102
|
def expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
|
99
|
-
args = [:expireat, key, unix_time]
|
103
|
+
args = [:expireat, key, Integer(unix_time)]
|
100
104
|
args << "NX" if nx
|
101
105
|
args << "XX" if xx
|
102
106
|
args << "GT" if gt
|
@@ -105,6 +109,14 @@ class Redis
|
|
105
109
|
send_command(args, &Boolify)
|
106
110
|
end
|
107
111
|
|
112
|
+
# Get a key's expiry time specified as number of seconds from UNIX Epoch
|
113
|
+
#
|
114
|
+
# @param [String] key
|
115
|
+
# @return [Integer] expiry time specified as number of seconds from UNIX Epoch
|
116
|
+
def expiretime(key)
|
117
|
+
send_command([:expiretime, key])
|
118
|
+
end
|
119
|
+
|
108
120
|
# Get the time to live (in seconds) for a key.
|
109
121
|
#
|
110
122
|
# @param [String] key
|
@@ -132,7 +144,7 @@ class Redis
|
|
132
144
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
133
145
|
# @return [Boolean] whether the timeout was set or not
|
134
146
|
def pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil)
|
135
|
-
args = [:pexpire, key, milliseconds]
|
147
|
+
args = [:pexpire, key, Integer(milliseconds)]
|
136
148
|
args << "NX" if nx
|
137
149
|
args << "XX" if xx
|
138
150
|
args << "GT" if gt
|
@@ -152,7 +164,7 @@ class Redis
|
|
152
164
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
153
165
|
# @return [Boolean] whether the timeout was set or not
|
154
166
|
def pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
|
155
|
-
args = [:pexpireat, key, ms_unix_time]
|
167
|
+
args = [:pexpireat, key, Integer(ms_unix_time)]
|
156
168
|
args << "NX" if nx
|
157
169
|
args << "XX" if xx
|
158
170
|
args << "GT" if gt
|
@@ -161,6 +173,14 @@ class Redis
|
|
161
173
|
send_command(args, &Boolify)
|
162
174
|
end
|
163
175
|
|
176
|
+
# Get a key's expiry time specified as number of milliseconds from UNIX Epoch
|
177
|
+
#
|
178
|
+
# @param [String] key
|
179
|
+
# @return [Integer] expiry time specified as number of milliseconds from UNIX Epoch
|
180
|
+
def pexpiretime(key)
|
181
|
+
send_command([:pexpiretime, key])
|
182
|
+
end
|
183
|
+
|
164
184
|
# Get the time to live (in milliseconds) for a key.
|
165
185
|
#
|
166
186
|
# @param [String] key
|
@@ -249,24 +269,6 @@ class Redis
|
|
249
269
|
# @param [String, Array<String>] keys
|
250
270
|
# @return [Integer]
|
251
271
|
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
272
|
send_command([:exists, *keys])
|
271
273
|
end
|
272
274
|
|
@@ -284,6 +286,8 @@ class Redis
|
|
284
286
|
#
|
285
287
|
# @param [String] pattern
|
286
288
|
# @return [Array<String>]
|
289
|
+
#
|
290
|
+
# See the [Redis Server KEYS documentation](https://redis.io/docs/latest/commands/keys/) for further details
|
287
291
|
def keys(pattern = "*")
|
288
292
|
send_command([:keys, pattern]) do |reply|
|
289
293
|
if reply.is_a?(String)
|
@@ -445,7 +449,7 @@ class Redis
|
|
445
449
|
|
446
450
|
args << cursor
|
447
451
|
args << "MATCH" << match if match
|
448
|
-
args << "COUNT" << count if count
|
452
|
+
args << "COUNT" << Integer(count) if count
|
449
453
|
args << "TYPE" << type if type
|
450
454
|
|
451
455
|
send_command([command] + args, &block)
|
data/lib/redis/commands/lists.rb
CHANGED
@@ -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 =>
|
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,23 +173,77 @@ 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,
|
181
|
+
def brpoplpush(source, destination, timeout: 0)
|
182
182
|
command = [:brpoplpush, source, destination, timeout]
|
183
183
|
send_blocking_command(command, timeout)
|
184
184
|
end
|
185
185
|
|
186
|
+
# Pops one or more elements from the first non-empty list key from the list
|
187
|
+
# of provided key names. If lists are empty, blocks until timeout has passed.
|
188
|
+
#
|
189
|
+
# @example Popping a element
|
190
|
+
# redis.blmpop(1.0, 'list')
|
191
|
+
# #=> ['list', ['a']]
|
192
|
+
# @example With count option
|
193
|
+
# redis.blmpop(1.0, 'list', count: 2)
|
194
|
+
# #=> ['list', ['a', 'b']]
|
195
|
+
#
|
196
|
+
# @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
|
197
|
+
# A timeout of zero can be used to block indefinitely.
|
198
|
+
# @params key [String, Array<String>] one or more keys with lists
|
199
|
+
# @params modifier [String]
|
200
|
+
# - when `"LEFT"` - the elements popped are those from the left of the list
|
201
|
+
# - when `"RIGHT"` - the elements popped are those from the right of the list
|
202
|
+
# @params count [Integer] a number of elements to pop
|
203
|
+
#
|
204
|
+
# @return [Array<String, Array<String, Float>>] list of popped elements or nil
|
205
|
+
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
|
206
|
+
raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
|
207
|
+
|
208
|
+
args = [:blmpop, timeout, keys.size, *keys, modifier]
|
209
|
+
args << "COUNT" << Integer(count) if count
|
210
|
+
|
211
|
+
send_blocking_command(args, timeout)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Pops one or more elements from the first non-empty list key from the list
|
215
|
+
# of provided key names.
|
216
|
+
#
|
217
|
+
# @example Popping a element
|
218
|
+
# redis.lmpop('list')
|
219
|
+
# #=> ['list', ['a']]
|
220
|
+
# @example With count option
|
221
|
+
# redis.lmpop('list', count: 2)
|
222
|
+
# #=> ['list', ['a', 'b']]
|
223
|
+
#
|
224
|
+
# @params key [String, Array<String>] one or more keys with lists
|
225
|
+
# @params modifier [String]
|
226
|
+
# - when `"LEFT"` - the elements popped are those from the left of the list
|
227
|
+
# - when `"RIGHT"` - the elements popped are those from the right of the list
|
228
|
+
# @params count [Integer] a number of elements to pop
|
229
|
+
#
|
230
|
+
# @return [Array<String, Array<String, Float>>] list of popped elements or nil
|
231
|
+
def lmpop(*keys, modifier: "LEFT", count: nil)
|
232
|
+
raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"
|
233
|
+
|
234
|
+
args = [:lmpop, keys.size, *keys, modifier]
|
235
|
+
args << "COUNT" << Integer(count) if count
|
236
|
+
|
237
|
+
send_command(args)
|
238
|
+
end
|
239
|
+
|
186
240
|
# Get an element from a list by its index.
|
187
241
|
#
|
188
242
|
# @param [String] key
|
189
243
|
# @param [Integer] index
|
190
244
|
# @return [String]
|
191
245
|
def lindex(key, index)
|
192
|
-
send_command([:lindex, key, index])
|
246
|
+
send_command([:lindex, key, Integer(index)])
|
193
247
|
end
|
194
248
|
|
195
249
|
# Insert an element before or after another element in a list.
|
@@ -211,7 +265,7 @@ class Redis
|
|
211
265
|
# @param [Integer] stop stop index
|
212
266
|
# @return [Array<String>]
|
213
267
|
def lrange(key, start, stop)
|
214
|
-
send_command([:lrange, key, start, stop])
|
268
|
+
send_command([:lrange, key, Integer(start), Integer(stop)])
|
215
269
|
end
|
216
270
|
|
217
271
|
# Remove elements from a list.
|
@@ -224,7 +278,7 @@ class Redis
|
|
224
278
|
# @param [String] value
|
225
279
|
# @return [Integer] the number of removed elements
|
226
280
|
def lrem(key, count, value)
|
227
|
-
send_command([:lrem, key, count, value])
|
281
|
+
send_command([:lrem, key, Integer(count), value])
|
228
282
|
end
|
229
283
|
|
230
284
|
# Set the value of an element in a list by its index.
|
@@ -234,7 +288,7 @@ class Redis
|
|
234
288
|
# @param [String] value
|
235
289
|
# @return [String] `OK`
|
236
290
|
def lset(key, index, value)
|
237
|
-
send_command([:lset, key, index, value])
|
291
|
+
send_command([:lset, key, Integer(index), value])
|
238
292
|
end
|
239
293
|
|
240
294
|
# Trim a list to the specified range.
|
@@ -244,7 +298,7 @@ class Redis
|
|
244
298
|
# @param [Integer] stop stop index
|
245
299
|
# @return [String] `OK`
|
246
300
|
def ltrim(key, start, stop)
|
247
|
-
send_command([:ltrim, key, start, stop])
|
301
|
+
send_command([:ltrim, key, Integer(start), Integer(stop)])
|
248
302
|
end
|
249
303
|
|
250
304
|
private
|
@@ -253,21 +307,16 @@ class Redis
|
|
253
307
|
timeout = if args.last.is_a?(Hash)
|
254
308
|
options = args.pop
|
255
309
|
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
310
|
end
|
265
311
|
|
266
312
|
timeout ||= 0
|
313
|
+
unless timeout.is_a?(Integer) || timeout.is_a?(Float)
|
314
|
+
raise ArgumentError, "timeout must be an Integer or Float, got: #{timeout.class}"
|
315
|
+
end
|
267
316
|
|
268
|
-
|
269
|
-
|
270
|
-
command
|
317
|
+
args.flatten!(1)
|
318
|
+
command = [cmd].concat(args)
|
319
|
+
command << timeout
|
271
320
|
send_blocking_command(command, timeout, &blk)
|
272
321
|
end
|
273
322
|
|
@@ -9,57 +9,45 @@ class Redis
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def subscribed?
|
12
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
32
|
+
# See the [Redis Server PSUBSCRIBE documentation](https://redis.io/docs/latest/commands/psubscribe/)
|
33
|
+
# for further details
|
42
34
|
def psubscribe(*channels, &block)
|
43
|
-
|
44
|
-
_subscription(:psubscribe, 0, channels, block)
|
45
|
-
end
|
35
|
+
_subscription(:psubscribe, 0, channels, block)
|
46
36
|
end
|
47
37
|
|
48
38
|
# Listen for messages published to channels matching the given patterns.
|
49
39
|
# Throw a timeout error if there is no messages for a timeout period.
|
40
|
+
# See the [Redis Server PSUBSCRIBE documentation](https://redis.io/docs/latest/commands/psubscribe/)
|
41
|
+
# for further details
|
50
42
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
51
|
-
|
52
|
-
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
53
|
-
end
|
43
|
+
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
54
44
|
end
|
55
45
|
|
56
46
|
# Stop listening for messages posted to channels matching the given patterns.
|
47
|
+
# See the [Redis Server PUNSUBSCRIBE documentation](https://redis.io/docs/latest/commands/punsubscribe/)
|
48
|
+
# for further details
|
57
49
|
def punsubscribe(*channels)
|
58
|
-
|
59
|
-
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
60
|
-
|
61
|
-
client.punsubscribe(*channels)
|
62
|
-
end
|
50
|
+
_subscription(:punsubscribe, 0, channels, nil)
|
63
51
|
end
|
64
52
|
|
65
53
|
# Inspect the state of the Pub/Sub subsystem.
|
@@ -67,6 +55,27 @@ class Redis
|
|
67
55
|
def pubsub(subcommand, *args)
|
68
56
|
send_command([:pubsub, subcommand] + args)
|
69
57
|
end
|
58
|
+
|
59
|
+
# Post a message to a channel in a shard.
|
60
|
+
def spublish(channel, message)
|
61
|
+
send_command([:spublish, channel, message])
|
62
|
+
end
|
63
|
+
|
64
|
+
# Listen for messages published to the given channels in a shard.
|
65
|
+
def ssubscribe(*channels, &block)
|
66
|
+
_subscription(:ssubscribe, 0, channels, block)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Listen for messages published to the given channels in a shard.
|
70
|
+
# Throw a timeout error if there is no messages for a timeout period.
|
71
|
+
def ssubscribe_with_timeout(timeout, *channels, &block)
|
72
|
+
_subscription(:ssubscribe_with_timeout, timeout, channels, block)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Stop listening for messages posted to the given channels in a shard.
|
76
|
+
def sunsubscribe(*channels)
|
77
|
+
_subscription(:sunsubscribe, 0, channels, nil)
|
78
|
+
end
|
70
79
|
end
|
71
80
|
end
|
72
81
|
end
|
@@ -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
|
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
|
120
|
+
def monitor
|
121
121
|
synchronize do |client|
|
122
|
-
client.
|
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.
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
159
|
-
|
160
|
-
|
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.
|