redis 4.1.0 → 4.2.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 +5 -5
- data/CHANGELOG.md +44 -0
- data/README.md +63 -5
- data/lib/redis.rb +473 -459
- data/lib/redis/client.rb +95 -78
- data/lib/redis/cluster.rb +13 -4
- data/lib/redis/cluster/node.rb +3 -0
- data/lib/redis/cluster/node_key.rb +3 -7
- data/lib/redis/cluster/option.rb +27 -14
- data/lib/redis/cluster/slot.rb +30 -13
- data/lib/redis/cluster/slot_loader.rb +4 -4
- data/lib/redis/connection.rb +2 -0
- data/lib/redis/connection/command_helper.rb +3 -2
- data/lib/redis/connection/hiredis.rb +4 -3
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +69 -59
- data/lib/redis/connection/synchrony.rb +9 -4
- data/lib/redis/distributed.rb +81 -55
- data/lib/redis/errors.rb +2 -0
- data/lib/redis/hash_ring.rb +15 -14
- data/lib/redis/pipeline.rb +46 -8
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- metadata +6 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9796f6646b7d3aaeeb5ef37629fb1a43422285724d8d2901a219ef4f2882eff5
|
4
|
+
data.tar.gz: b89f4f1d6a3c9ee93202ce08cdcd3ed184694b5693f7461be7cf7e517139a278
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be709e1aad1acee8d7c3e121e946060ce9b693ac80e25af200e2a579988f3952d6522cb9855917dc76628ae2038365bb8754b49a7cc6e90395706ba30fc87a86
|
7
|
+
data.tar.gz: 00102b01b4b37daab76fc90990f980a4710bec0e797a70d65a7544ef304f01f9b9babbdcc680da71513dd8f79649bd5f529e6804e71297b26978625bea746367
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,49 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.2.0
|
4
|
+
|
5
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
6
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
7
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
8
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
9
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
10
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
11
|
+
* Support `keepttl` ooption in `set`. See #913.
|
12
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
13
|
+
* Accept sentinel options even with string key. See #599.
|
14
|
+
* Verify TLS connections by default. See #900.
|
15
|
+
|
16
|
+
# 4.1.4
|
17
|
+
|
18
|
+
* Alias `Redis#disconnect` as `#close`. See #901.
|
19
|
+
* Handle clusters with multiple slot ranges. See #894.
|
20
|
+
* Fix password authentication to a redis cluster. See #889.
|
21
|
+
* Handle recursive MOVED responses. See #882.
|
22
|
+
* Increase buffer size in the ruby connector. See #880.
|
23
|
+
* Fix thread safety of `Redis.queue`. See #878.
|
24
|
+
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
25
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
26
|
+
|
27
|
+
# 4.1.3
|
28
|
+
|
29
|
+
* Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
|
30
|
+
|
31
|
+
# 4.1.2
|
32
|
+
|
33
|
+
* Fix several authentication problems with sentinel. See #850 and #856.
|
34
|
+
* Explicitly drop Ruby 2.2 support.
|
35
|
+
|
36
|
+
|
37
|
+
# 4.1.1
|
38
|
+
|
39
|
+
* Fix error handling in multi blocks. See #754.
|
40
|
+
* Fix geoadd to accept arrays like georadius and georadiusbymember. See #841.
|
41
|
+
* Fix georadius command failing when long == lat. See #841.
|
42
|
+
* Fix timeout error in xread block: 0. See #837.
|
43
|
+
* Fix incompatibility issue with redis-objects. See #834.
|
44
|
+
* Properly handle Errno::EADDRNOTAVAIL on connect.
|
45
|
+
* Fix password authentication to sentinel instances. See #813.
|
46
|
+
|
3
47
|
# 4.1.0
|
4
48
|
|
5
49
|
* Add Redis Cluster support. See #716.
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
# redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link]
|
1
|
+
# redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link] 
|
2
2
|
|
3
3
|
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
|
4
4
|
providing an idiomatic interface.
|
5
5
|
|
6
|
+
See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
|
6
7
|
|
7
8
|
## Getting started
|
8
9
|
|
@@ -34,6 +35,9 @@ You can also specify connection options as a [`redis://` URL][redis-url]:
|
|
34
35
|
redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
35
36
|
```
|
36
37
|
|
38
|
+
The client expects passwords with special chracters to be URL-encoded (i.e.
|
39
|
+
`CGI.escape(password)`).
|
40
|
+
|
37
41
|
By default, the client will try to read the `REDIS_URL` environment variable
|
38
42
|
and use that as URL to connect to. The above statement is therefore equivalent
|
39
43
|
to setting this environment variable and calling `Redis.new` without arguments.
|
@@ -95,10 +99,60 @@ but a few so that if one is down the client will try the next one. The client
|
|
95
99
|
is able to remember the last Sentinel that was able to reply correctly and will
|
96
100
|
use it for the next requests.
|
97
101
|
|
102
|
+
If you want to [authenticate](https://redis.io/topics/sentinel#configuring-sentinel-instances-with-authentication) Sentinel itself, you must specify the `password` option per instance.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
|
106
|
+
{ host: '127.0.0.1', port: 26381, password: 'mysecret' }]
|
107
|
+
|
108
|
+
redis = Redis.new(host: 'mymaster', sentinels: SENTINELS, role: :master)
|
109
|
+
```
|
110
|
+
|
111
|
+
## Cluster support
|
112
|
+
|
113
|
+
`redis-rb` supports [clustering](https://redis.io/topics/cluster-spec).
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
# Nodes can be passed to the client as an array of connection URLs.
|
117
|
+
nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
|
118
|
+
redis = Redis.new(cluster: nodes)
|
119
|
+
|
120
|
+
# You can also specify the options as a Hash. The options are the same as for a single server connection.
|
121
|
+
(7000..7005).map { |port| { host: '127.0.0.1', port: port } }
|
122
|
+
```
|
123
|
+
|
124
|
+
You can also specify only a subset of the nodes, and the client will discover the missing ones using the [CLUSTER NODES](https://redis.io/commands/cluster-nodes) command.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
Redis.new(cluster: %w[redis://127.0.0.1:7000])
|
128
|
+
```
|
129
|
+
|
130
|
+
If you want [the connection to be able to read from any replica](https://redis.io/commands/readonly), you must pass the `replica: true`. Note that this connection won't be usable to write keys.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
Redis.new(cluster: nodes, replica: true)
|
134
|
+
```
|
135
|
+
|
136
|
+
The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
|
140
|
+
|
141
|
+
redis.mget('key1', 'key2')
|
142
|
+
#=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
|
143
|
+
|
144
|
+
redis.mget('{key}1', '{key}2')
|
145
|
+
#=> [nil, nil]
|
146
|
+
```
|
147
|
+
|
148
|
+
* The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
|
149
|
+
* The client support permanent node failures, and will reroute requests to promoted slaves.
|
150
|
+
* The client supports `MOVED` and `ASK` redirections transparently.
|
151
|
+
|
98
152
|
## Storing objects
|
99
153
|
|
100
|
-
Redis
|
101
|
-
|
154
|
+
Redis "string" types can be used to store serialized Ruby objects, for
|
155
|
+
example with JSON:
|
102
156
|
|
103
157
|
```ruby
|
104
158
|
require "json"
|
@@ -272,7 +326,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
272
326
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
273
327
|
or [ghostunnel].
|
274
328
|
|
275
|
-
To enable SSL support, pass the `:ssl =>
|
329
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
276
330
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
277
331
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
278
332
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -387,6 +441,10 @@ redis = Redis.new(:driver => :synchrony)
|
|
387
441
|
This library is tested against recent Ruby and Redis versions.
|
388
442
|
Check [Travis][travis-link] for the exact versions supported.
|
389
443
|
|
444
|
+
## See Also
|
445
|
+
|
446
|
+
- [async-redis](https://github.com/socketry/async-redis) — An [async](https://github.com/socketry/async) compatible Redis client.
|
447
|
+
|
390
448
|
## Contributors
|
391
449
|
|
392
450
|
Several people contributed to redis-rb, but we would like to especially
|
@@ -397,7 +455,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
397
455
|
## Contributing
|
398
456
|
|
399
457
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
400
|
-
requests.
|
458
|
+
requests.
|
401
459
|
|
402
460
|
|
403
461
|
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
data/lib/redis.rb
CHANGED
@@ -1,33 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "monitor"
|
2
4
|
require_relative "redis/errors"
|
3
5
|
|
4
6
|
class Redis
|
7
|
+
class << self
|
8
|
+
attr_accessor :exists_returns_integer
|
9
|
+
attr_writer :current
|
10
|
+
end
|
5
11
|
|
6
12
|
def self.current
|
7
13
|
@current ||= Redis.new
|
8
14
|
end
|
9
15
|
|
10
|
-
def self.current=(redis)
|
11
|
-
@current = redis
|
12
|
-
end
|
13
|
-
|
14
16
|
include MonitorMixin
|
15
17
|
|
16
18
|
# Create a new client instance
|
17
19
|
#
|
18
20
|
# @param [Hash] options
|
19
|
-
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
21
|
+
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
22
|
+
# `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
|
23
|
+
# connection: `unix://[path to Redis socket]`. This overrides all other options.
|
20
24
|
# @option options [String] :host ("127.0.0.1") server hostname
|
21
|
-
# @option options [
|
25
|
+
# @option options [Integer] :port (6379) server port
|
22
26
|
# @option options [String] :path path to server socket (overrides host and port)
|
23
27
|
# @option options [Float] :timeout (5.0) timeout in seconds
|
24
28
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
25
29
|
# @option options [String] :password Password to authenticate against server
|
26
|
-
# @option options [
|
30
|
+
# @option options [Integer] :db (0) Database to select after initial connect
|
27
31
|
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
28
|
-
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
29
|
-
#
|
30
|
-
# @option options [
|
32
|
+
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
33
|
+
# `CLIENT SETNAME`
|
34
|
+
# @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
|
35
|
+
# based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
|
36
|
+
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
31
37
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
32
38
|
# @option options [Array] :sentinels List of sentinels to contact
|
33
39
|
# @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
|
@@ -51,7 +57,7 @@ class Redis
|
|
51
57
|
end
|
52
58
|
|
53
59
|
# Run code with the client reconnecting
|
54
|
-
def with_reconnect(val=true, &blk)
|
60
|
+
def with_reconnect(val = true, &blk)
|
55
61
|
synchronize do |client|
|
56
62
|
client.with_reconnect(val, &blk)
|
57
63
|
end
|
@@ -94,7 +100,9 @@ class Redis
|
|
94
100
|
# See http://redis.io/topics/pipelining for more details.
|
95
101
|
#
|
96
102
|
def queue(*command)
|
97
|
-
|
103
|
+
synchronize do
|
104
|
+
@queue[Thread.current.object_id] << command
|
105
|
+
end
|
98
106
|
end
|
99
107
|
|
100
108
|
# Sends all commands in the queue.
|
@@ -104,7 +112,12 @@ class Redis
|
|
104
112
|
def commit
|
105
113
|
synchronize do |client|
|
106
114
|
begin
|
107
|
-
|
115
|
+
pipeline = Pipeline.new(client)
|
116
|
+
@queue[Thread.current.object_id].each do |command|
|
117
|
+
pipeline.call(command)
|
118
|
+
end
|
119
|
+
|
120
|
+
client.call_pipelined(pipeline)
|
108
121
|
ensure
|
109
122
|
@queue.delete(Thread.current.object_id)
|
110
123
|
end
|
@@ -128,7 +141,7 @@ class Redis
|
|
128
141
|
|
129
142
|
# Change the selected database for the current connection.
|
130
143
|
#
|
131
|
-
# @param [
|
144
|
+
# @param [Integer] db zero-based index of the DB to use (0 to 15)
|
132
145
|
# @return [String] `OK`
|
133
146
|
def select(db)
|
134
147
|
synchronize do |client|
|
@@ -197,7 +210,7 @@ class Redis
|
|
197
210
|
def config(action, *args)
|
198
211
|
synchronize do |client|
|
199
212
|
client.call([:config, action] + args) do |reply|
|
200
|
-
if reply.
|
213
|
+
if reply.is_a?(Array) && action == :get
|
201
214
|
Hashify.call(reply)
|
202
215
|
else
|
203
216
|
reply
|
@@ -227,7 +240,7 @@ class Redis
|
|
227
240
|
|
228
241
|
# Return the number of keys in the selected database.
|
229
242
|
#
|
230
|
-
# @return [
|
243
|
+
# @return [Integer]
|
231
244
|
def dbsize
|
232
245
|
synchronize do |client|
|
233
246
|
client.call([:dbsize])
|
@@ -248,7 +261,7 @@ class Redis
|
|
248
261
|
def flushall(options = nil)
|
249
262
|
synchronize do |client|
|
250
263
|
if options && options[:async]
|
251
|
-
client.call([
|
264
|
+
client.call(%i[flushall async])
|
252
265
|
else
|
253
266
|
client.call([:flushall])
|
254
267
|
end
|
@@ -263,7 +276,7 @@ class Redis
|
|
263
276
|
def flushdb(options = nil)
|
264
277
|
synchronize do |client|
|
265
278
|
if options && options[:async]
|
266
|
-
client.call([
|
279
|
+
client.call(%i[flushdb async])
|
267
280
|
else
|
268
281
|
client.call([:flushdb])
|
269
282
|
end
|
@@ -277,7 +290,7 @@ class Redis
|
|
277
290
|
def info(cmd = nil)
|
278
291
|
synchronize do |client|
|
279
292
|
client.call([:info, cmd].compact) do |reply|
|
280
|
-
if reply.
|
293
|
+
if reply.is_a?(String)
|
281
294
|
reply = HashifyInfo.call(reply)
|
282
295
|
|
283
296
|
if cmd && cmd.to_s == "commandstats"
|
@@ -296,7 +309,7 @@ class Redis
|
|
296
309
|
|
297
310
|
# Get the UNIX time stamp of the last successful save to disk.
|
298
311
|
#
|
299
|
-
# @return [
|
312
|
+
# @return [Integer]
|
300
313
|
def lastsave
|
301
314
|
synchronize do |client|
|
302
315
|
client.call([:lastsave])
|
@@ -348,9 +361,9 @@ class Redis
|
|
348
361
|
# Interact with the slowlog (get, len, reset)
|
349
362
|
#
|
350
363
|
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
351
|
-
# @param [
|
352
|
-
# @return [Array<String>,
|
353
|
-
def slowlog(subcommand, length=nil)
|
364
|
+
# @param [Integer] length maximum number of entries to return
|
365
|
+
# @return [Array<String>, Integer, String] depends on subcommand
|
366
|
+
def slowlog(subcommand, length = nil)
|
354
367
|
synchronize do |client|
|
355
368
|
args = [:slowlog, subcommand]
|
356
369
|
args << length if length
|
@@ -370,12 +383,12 @@ class Redis
|
|
370
383
|
# @example
|
371
384
|
# r.time # => [ 1333093196, 606806 ]
|
372
385
|
#
|
373
|
-
# @return [Array<
|
386
|
+
# @return [Array<Integer>] tuple of seconds since UNIX epoch and
|
374
387
|
# microseconds in the current second
|
375
388
|
def time
|
376
389
|
synchronize do |client|
|
377
390
|
client.call([:time]) do |reply|
|
378
|
-
reply
|
391
|
+
reply&.map(&:to_i)
|
379
392
|
end
|
380
393
|
end
|
381
394
|
end
|
@@ -393,7 +406,7 @@ class Redis
|
|
393
406
|
# Set a key's time to live in seconds.
|
394
407
|
#
|
395
408
|
# @param [String] key
|
396
|
-
# @param [
|
409
|
+
# @param [Integer] seconds time to live
|
397
410
|
# @return [Boolean] whether the timeout was set or not
|
398
411
|
def expire(key, seconds)
|
399
412
|
synchronize do |client|
|
@@ -404,7 +417,7 @@ class Redis
|
|
404
417
|
# Set the expiration for a key as a UNIX timestamp.
|
405
418
|
#
|
406
419
|
# @param [String] key
|
407
|
-
# @param [
|
420
|
+
# @param [Integer] unix_time expiry time specified as a UNIX timestamp
|
408
421
|
# @return [Boolean] whether the timeout was set or not
|
409
422
|
def expireat(key, unix_time)
|
410
423
|
synchronize do |client|
|
@@ -415,7 +428,7 @@ class Redis
|
|
415
428
|
# Get the time to live (in seconds) for a key.
|
416
429
|
#
|
417
430
|
# @param [String] key
|
418
|
-
# @return [
|
431
|
+
# @return [Integer] remaining time to live in seconds.
|
419
432
|
#
|
420
433
|
# In Redis 2.6 or older the command returns -1 if the key does not exist or if
|
421
434
|
# the key exist but has no associated expire.
|
@@ -433,7 +446,7 @@ class Redis
|
|
433
446
|
# Set a key's time to live in milliseconds.
|
434
447
|
#
|
435
448
|
# @param [String] key
|
436
|
-
# @param [
|
449
|
+
# @param [Integer] milliseconds time to live
|
437
450
|
# @return [Boolean] whether the timeout was set or not
|
438
451
|
def pexpire(key, milliseconds)
|
439
452
|
synchronize do |client|
|
@@ -444,7 +457,7 @@ class Redis
|
|
444
457
|
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
|
445
458
|
#
|
446
459
|
# @param [String] key
|
447
|
-
# @param [
|
460
|
+
# @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
|
448
461
|
# @return [Boolean] whether the timeout was set or not
|
449
462
|
def pexpireat(key, ms_unix_time)
|
450
463
|
synchronize do |client|
|
@@ -455,7 +468,7 @@ class Redis
|
|
455
468
|
# Get the time to live (in milliseconds) for a key.
|
456
469
|
#
|
457
470
|
# @param [String] key
|
458
|
-
# @return [
|
471
|
+
# @return [Integer] remaining time to live in milliseconds
|
459
472
|
# In Redis 2.6 or older the command returns -1 if the key does not exist or if
|
460
473
|
# the key exist but has no associated expire.
|
461
474
|
#
|
@@ -488,9 +501,9 @@ class Redis
|
|
488
501
|
# - `:replace => Boolean`: if false, raises an error if key already exists
|
489
502
|
# @raise [Redis::CommandError]
|
490
503
|
# @return [String] `"OK"`
|
491
|
-
def restore(key, ttl, serialized_value,
|
504
|
+
def restore(key, ttl, serialized_value, replace: nil)
|
492
505
|
args = [:restore, key, ttl, serialized_value]
|
493
|
-
args << 'REPLACE' if
|
506
|
+
args << 'REPLACE' if replace
|
494
507
|
|
495
508
|
synchronize do |client|
|
496
509
|
client.call(args)
|
@@ -525,7 +538,7 @@ class Redis
|
|
525
538
|
# Delete one or more keys.
|
526
539
|
#
|
527
540
|
# @param [String, Array<String>] keys
|
528
|
-
# @return [
|
541
|
+
# @return [Integer] number of keys that were deleted
|
529
542
|
def del(*keys)
|
530
543
|
synchronize do |client|
|
531
544
|
client.call([:del] + keys)
|
@@ -535,20 +548,43 @@ class Redis
|
|
535
548
|
# Unlink one or more keys.
|
536
549
|
#
|
537
550
|
# @param [String, Array<String>] keys
|
538
|
-
# @return [
|
551
|
+
# @return [Integer] number of keys that were unlinked
|
539
552
|
def unlink(*keys)
|
540
553
|
synchronize do |client|
|
541
554
|
client.call([:unlink] + keys)
|
542
555
|
end
|
543
556
|
end
|
544
557
|
|
545
|
-
# Determine
|
558
|
+
# Determine how many of the keys exists.
|
546
559
|
#
|
547
|
-
# @param [String]
|
560
|
+
# @param [String, Array<String>] keys
|
561
|
+
# @return [Integer]
|
562
|
+
def exists(*keys)
|
563
|
+
if !Redis.exists_returns_integer && keys.size == 1
|
564
|
+
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
|
565
|
+
"use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
|
566
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
567
|
+
|
568
|
+
::Kernel.warn(message)
|
569
|
+
exists?(*keys)
|
570
|
+
else
|
571
|
+
_exists(*keys)
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
def _exists(*keys)
|
576
|
+
synchronize do |client|
|
577
|
+
client.call([:exists, *keys])
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
# Determine if any of the keys exists.
|
582
|
+
#
|
583
|
+
# @param [String, Array<String>] keys
|
548
584
|
# @return [Boolean]
|
549
|
-
def exists(
|
585
|
+
def exists?(*keys)
|
550
586
|
synchronize do |client|
|
551
|
-
client.call([:exists,
|
587
|
+
client.call([:exists, *keys], &Boolify)
|
552
588
|
end
|
553
589
|
end
|
554
590
|
|
@@ -559,7 +595,7 @@ class Redis
|
|
559
595
|
def keys(pattern = "*")
|
560
596
|
synchronize do |client|
|
561
597
|
client.call([:keys, pattern]) do |reply|
|
562
|
-
if reply.
|
598
|
+
if reply.is_a?(String)
|
563
599
|
reply.split(" ")
|
564
600
|
else
|
565
601
|
reply
|
@@ -585,7 +621,7 @@ class Redis
|
|
585
621
|
# # => "bar"
|
586
622
|
#
|
587
623
|
# @param [String] key
|
588
|
-
# @param [
|
624
|
+
# @param [Integer] db
|
589
625
|
# @return [Boolean] whether the key was moved or not
|
590
626
|
def move(key, db)
|
591
627
|
synchronize do |client|
|
@@ -649,36 +685,33 @@ class Redis
|
|
649
685
|
# - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
|
650
686
|
# - `:store => String`: key to store the result at
|
651
687
|
#
|
652
|
-
# @return [Array<String>, Array<Array<String>>,
|
688
|
+
# @return [Array<String>, Array<Array<String>>, Integer]
|
653
689
|
# - when `:get` is not specified, or holds a single element, an array of elements
|
654
690
|
# - when `:get` is specified, and holds more than one element, an array of
|
655
691
|
# elements where every element is an array with the result for every
|
656
692
|
# element specified in `:get`
|
657
693
|
# - when `:store` is specified, the number of elements in the stored result
|
658
|
-
def sort(key,
|
659
|
-
args = []
|
660
|
-
|
661
|
-
by = options[:by]
|
662
|
-
args.concat(["BY", by]) if by
|
694
|
+
def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
|
695
|
+
args = [:sort, key]
|
696
|
+
args << "BY" << by if by
|
663
697
|
|
664
|
-
|
665
|
-
|
698
|
+
if limit
|
699
|
+
args << "LIMIT"
|
700
|
+
args.concat(limit)
|
701
|
+
end
|
666
702
|
|
667
|
-
get = Array(
|
668
|
-
|
703
|
+
get = Array(get)
|
704
|
+
get.each do |item|
|
705
|
+
args << "GET" << item
|
706
|
+
end
|
669
707
|
|
670
|
-
order = options[:order]
|
671
708
|
args.concat(order.split(" ")) if order
|
672
|
-
|
673
|
-
store = options[:store]
|
674
|
-
args.concat(["STORE", store]) if store
|
709
|
+
args << "STORE" << store if store
|
675
710
|
|
676
711
|
synchronize do |client|
|
677
|
-
client.call(
|
712
|
+
client.call(args) do |reply|
|
678
713
|
if get.size > 1 && !store
|
679
|
-
if reply
|
680
|
-
reply.each_slice(get.size).to_a
|
681
|
-
end
|
714
|
+
reply.each_slice(get.size).to_a if reply
|
682
715
|
else
|
683
716
|
reply
|
684
717
|
end
|
@@ -703,7 +736,7 @@ class Redis
|
|
703
736
|
# # => 4
|
704
737
|
#
|
705
738
|
# @param [String] key
|
706
|
-
# @return [
|
739
|
+
# @return [Integer] value after decrementing it
|
707
740
|
def decr(key)
|
708
741
|
synchronize do |client|
|
709
742
|
client.call([:decr, key])
|
@@ -717,8 +750,8 @@ class Redis
|
|
717
750
|
# # => 0
|
718
751
|
#
|
719
752
|
# @param [String] key
|
720
|
-
# @param [
|
721
|
-
# @return [
|
753
|
+
# @param [Integer] decrement
|
754
|
+
# @return [Integer] value after decrementing it
|
722
755
|
def decrby(key, decrement)
|
723
756
|
synchronize do |client|
|
724
757
|
client.call([:decrby, key, decrement])
|
@@ -732,7 +765,7 @@ class Redis
|
|
732
765
|
# # => 6
|
733
766
|
#
|
734
767
|
# @param [String] key
|
735
|
-
# @return [
|
768
|
+
# @return [Integer] value after incrementing it
|
736
769
|
def incr(key)
|
737
770
|
synchronize do |client|
|
738
771
|
client.call([:incr, key])
|
@@ -746,8 +779,8 @@ class Redis
|
|
746
779
|
# # => 10
|
747
780
|
#
|
748
781
|
# @param [String] key
|
749
|
-
# @param [
|
750
|
-
# @return [
|
782
|
+
# @param [Integer] increment
|
783
|
+
# @return [Integer] value after incrementing it
|
751
784
|
def incrby(key, increment)
|
752
785
|
synchronize do |client|
|
753
786
|
client.call([:incrby, key, increment])
|
@@ -774,31 +807,25 @@ class Redis
|
|
774
807
|
# @param [String] key
|
775
808
|
# @param [String] value
|
776
809
|
# @param [Hash] options
|
777
|
-
# - `:ex =>
|
778
|
-
# - `:px =>
|
810
|
+
# - `:ex => Integer`: Set the specified expire time, in seconds.
|
811
|
+
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
779
812
|
# - `:nx => true`: Only set the key if it does not already exist.
|
780
813
|
# - `:xx => true`: Only set the key if it already exist.
|
814
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
781
815
|
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
782
|
-
def set(key, value,
|
783
|
-
args = []
|
784
|
-
|
785
|
-
|
786
|
-
args
|
787
|
-
|
788
|
-
|
789
|
-
args.concat(["PX", px]) if px
|
790
|
-
|
791
|
-
nx = options[:nx]
|
792
|
-
args.concat(["NX"]) if nx
|
793
|
-
|
794
|
-
xx = options[:xx]
|
795
|
-
args.concat(["XX"]) if xx
|
816
|
+
def set(key, value, ex: nil, px: nil, nx: nil, xx: nil, keepttl: nil)
|
817
|
+
args = [:set, key, value.to_s]
|
818
|
+
args << "EX" << ex if ex
|
819
|
+
args << "PX" << px if px
|
820
|
+
args << "NX" if nx
|
821
|
+
args << "XX" if xx
|
822
|
+
args << "KEEPTTL" if keepttl
|
796
823
|
|
797
824
|
synchronize do |client|
|
798
825
|
if nx || xx
|
799
|
-
client.call(
|
826
|
+
client.call(args, &BoolifySet)
|
800
827
|
else
|
801
|
-
client.call(
|
828
|
+
client.call(args)
|
802
829
|
end
|
803
830
|
end
|
804
831
|
end
|
@@ -806,7 +833,7 @@ class Redis
|
|
806
833
|
# Set the time to live in seconds of a key.
|
807
834
|
#
|
808
835
|
# @param [String] key
|
809
|
-
# @param [
|
836
|
+
# @param [Integer] ttl
|
810
837
|
# @param [String] value
|
811
838
|
# @return [String] `"OK"`
|
812
839
|
def setex(key, ttl, value)
|
@@ -818,7 +845,7 @@ class Redis
|
|
818
845
|
# Set the time to live in milliseconds of a key.
|
819
846
|
#
|
820
847
|
# @param [String] key
|
821
|
-
# @param [
|
848
|
+
# @param [Integer] ttl
|
822
849
|
# @param [String] value
|
823
850
|
# @return [String] `"OK"`
|
824
851
|
def psetex(key, ttl, value)
|
@@ -880,7 +907,7 @@ class Redis
|
|
880
907
|
# @see #mapped_msetnx
|
881
908
|
def msetnx(*args)
|
882
909
|
synchronize do |client|
|
883
|
-
client.call([:msetnx
|
910
|
+
client.call([:msetnx, *args], &Boolify)
|
884
911
|
end
|
885
912
|
end
|
886
913
|
|
@@ -911,7 +938,7 @@ class Redis
|
|
911
938
|
# Get the values of all the given keys.
|
912
939
|
#
|
913
940
|
# @example
|
914
|
-
# redis.mget("key1", "
|
941
|
+
# redis.mget("key1", "key2")
|
915
942
|
# # => ["v1", "v2"]
|
916
943
|
#
|
917
944
|
# @param [Array<String>] keys
|
@@ -920,7 +947,7 @@ class Redis
|
|
920
947
|
# @see #mapped_mget
|
921
948
|
def mget(*keys, &blk)
|
922
949
|
synchronize do |client|
|
923
|
-
client.call([:mget
|
950
|
+
client.call([:mget, *keys], &blk)
|
924
951
|
end
|
925
952
|
end
|
926
953
|
|
@@ -936,7 +963,7 @@ class Redis
|
|
936
963
|
# @see #mget
|
937
964
|
def mapped_mget(*keys)
|
938
965
|
mget(*keys) do |reply|
|
939
|
-
if reply.
|
966
|
+
if reply.is_a?(Array)
|
940
967
|
Hash[keys.zip(reply)]
|
941
968
|
else
|
942
969
|
reply
|
@@ -947,9 +974,9 @@ class Redis
|
|
947
974
|
# Overwrite part of a string at key starting at the specified offset.
|
948
975
|
#
|
949
976
|
# @param [String] key
|
950
|
-
# @param [
|
977
|
+
# @param [Integer] offset byte offset
|
951
978
|
# @param [String] value
|
952
|
-
# @return [
|
979
|
+
# @return [Integer] length of the string after it was modified
|
953
980
|
def setrange(key, offset, value)
|
954
981
|
synchronize do |client|
|
955
982
|
client.call([:setrange, key, offset, value.to_s])
|
@@ -959,10 +986,10 @@ class Redis
|
|
959
986
|
# Get a substring of the string stored at a key.
|
960
987
|
#
|
961
988
|
# @param [String] key
|
962
|
-
# @param [
|
963
|
-
# @param [
|
989
|
+
# @param [Integer] start zero-based start offset
|
990
|
+
# @param [Integer] stop zero-based end offset. Use -1 for representing
|
964
991
|
# the end of the string
|
965
|
-
# @return [
|
992
|
+
# @return [Integer] `0` or `1`
|
966
993
|
def getrange(key, start, stop)
|
967
994
|
synchronize do |client|
|
968
995
|
client.call([:getrange, key, start, stop])
|
@@ -972,9 +999,9 @@ class Redis
|
|
972
999
|
# Sets or clears the bit at offset in the string value stored at key.
|
973
1000
|
#
|
974
1001
|
# @param [String] key
|
975
|
-
# @param [
|
976
|
-
# @param [
|
977
|
-
# @return [
|
1002
|
+
# @param [Integer] offset bit offset
|
1003
|
+
# @param [Integer] value bit value `0` or `1`
|
1004
|
+
# @return [Integer] the original bit value stored at `offset`
|
978
1005
|
def setbit(key, offset, value)
|
979
1006
|
synchronize do |client|
|
980
1007
|
client.call([:setbit, key, offset, value])
|
@@ -984,8 +1011,8 @@ class Redis
|
|
984
1011
|
# Returns the bit value at offset in the string value stored at key.
|
985
1012
|
#
|
986
1013
|
# @param [String] key
|
987
|
-
# @param [
|
988
|
-
# @return [
|
1014
|
+
# @param [Integer] offset bit offset
|
1015
|
+
# @return [Integer] `0` or `1`
|
989
1016
|
def getbit(key, offset)
|
990
1017
|
synchronize do |client|
|
991
1018
|
client.call([:getbit, key, offset])
|
@@ -996,7 +1023,7 @@ class Redis
|
|
996
1023
|
#
|
997
1024
|
# @param [String] key
|
998
1025
|
# @param [String] value value to append
|
999
|
-
# @return [
|
1026
|
+
# @return [Integer] length of the string after appending
|
1000
1027
|
def append(key, value)
|
1001
1028
|
synchronize do |client|
|
1002
1029
|
client.call([:append, key, value])
|
@@ -1006,9 +1033,9 @@ class Redis
|
|
1006
1033
|
# Count the number of set bits in a range of the string value stored at key.
|
1007
1034
|
#
|
1008
1035
|
# @param [String] key
|
1009
|
-
# @param [
|
1010
|
-
# @param [
|
1011
|
-
# @return [
|
1036
|
+
# @param [Integer] start start index
|
1037
|
+
# @param [Integer] stop stop index
|
1038
|
+
# @return [Integer] the number of bits set to 1
|
1012
1039
|
def bitcount(key, start = 0, stop = -1)
|
1013
1040
|
synchronize do |client|
|
1014
1041
|
client.call([:bitcount, key, start, stop])
|
@@ -1020,25 +1047,23 @@ class Redis
|
|
1020
1047
|
# @param [String] operation e.g. `and`, `or`, `xor`, `not`
|
1021
1048
|
# @param [String] destkey destination key
|
1022
1049
|
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
1023
|
-
# @return [
|
1050
|
+
# @return [Integer] the length of the string stored in `destkey`
|
1024
1051
|
def bitop(operation, destkey, *keys)
|
1025
1052
|
synchronize do |client|
|
1026
|
-
client.call([:bitop, operation, destkey
|
1053
|
+
client.call([:bitop, operation, destkey, *keys])
|
1027
1054
|
end
|
1028
1055
|
end
|
1029
1056
|
|
1030
1057
|
# Return the position of the first bit set to 1 or 0 in a string.
|
1031
1058
|
#
|
1032
1059
|
# @param [String] key
|
1033
|
-
# @param [
|
1034
|
-
# @param [
|
1035
|
-
# @param [
|
1036
|
-
# @return [
|
1060
|
+
# @param [Integer] bit whether to look for the first 1 or 0 bit
|
1061
|
+
# @param [Integer] start start index
|
1062
|
+
# @param [Integer] stop stop index
|
1063
|
+
# @return [Integer] the position of the first 1/0 bit.
|
1037
1064
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
1038
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
1039
|
-
|
1040
|
-
raise(ArgumentError, 'stop parameter specified without start parameter')
|
1041
|
-
end
|
1065
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
1066
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
1042
1067
|
|
1043
1068
|
synchronize do |client|
|
1044
1069
|
command = [:bitpos, key, bit]
|
@@ -1063,7 +1088,7 @@ class Redis
|
|
1063
1088
|
# Get the length of the value stored in a key.
|
1064
1089
|
#
|
1065
1090
|
# @param [String] key
|
1066
|
-
# @return [
|
1091
|
+
# @return [Integer] the length of the value stored in the key, or 0
|
1067
1092
|
# if the key does not exist
|
1068
1093
|
def strlen(key)
|
1069
1094
|
synchronize do |client|
|
@@ -1074,7 +1099,7 @@ class Redis
|
|
1074
1099
|
# Get the length of a list.
|
1075
1100
|
#
|
1076
1101
|
# @param [String] key
|
1077
|
-
# @return [
|
1102
|
+
# @return [Integer]
|
1078
1103
|
def llen(key)
|
1079
1104
|
synchronize do |client|
|
1080
1105
|
client.call([:llen, key])
|
@@ -1085,7 +1110,7 @@ class Redis
|
|
1085
1110
|
#
|
1086
1111
|
# @param [String] key
|
1087
1112
|
# @param [String, Array<String>] value string value, or array of string values to push
|
1088
|
-
# @return [
|
1113
|
+
# @return [Integer] the length of the list after the push operation
|
1089
1114
|
def lpush(key, value)
|
1090
1115
|
synchronize do |client|
|
1091
1116
|
client.call([:lpush, key, value])
|
@@ -1096,7 +1121,7 @@ class Redis
|
|
1096
1121
|
#
|
1097
1122
|
# @param [String] key
|
1098
1123
|
# @param [String] value
|
1099
|
-
# @return [
|
1124
|
+
# @return [Integer] the length of the list after the push operation
|
1100
1125
|
def lpushx(key, value)
|
1101
1126
|
synchronize do |client|
|
1102
1127
|
client.call([:lpushx, key, value])
|
@@ -1107,7 +1132,7 @@ class Redis
|
|
1107
1132
|
#
|
1108
1133
|
# @param [String] key
|
1109
1134
|
# @param [String, Array<String>] value string value, or array of string values to push
|
1110
|
-
# @return [
|
1135
|
+
# @return [Integer] the length of the list after the push operation
|
1111
1136
|
def rpush(key, value)
|
1112
1137
|
synchronize do |client|
|
1113
1138
|
client.call([:rpush, key, value])
|
@@ -1118,7 +1143,7 @@ class Redis
|
|
1118
1143
|
#
|
1119
1144
|
# @param [String] key
|
1120
1145
|
# @param [String] value
|
1121
|
-
# @return [
|
1146
|
+
# @return [Integer] the length of the list after the push operation
|
1122
1147
|
def rpushx(key, value)
|
1123
1148
|
synchronize do |client|
|
1124
1149
|
client.call([:rpushx, key, value])
|
@@ -1157,21 +1182,21 @@ class Redis
|
|
1157
1182
|
end
|
1158
1183
|
|
1159
1184
|
def _bpop(cmd, args, &blk)
|
1160
|
-
|
1161
|
-
|
1162
|
-
if args.last.is_a?(Hash)
|
1185
|
+
timeout = if args.last.is_a?(Hash)
|
1163
1186
|
options = args.pop
|
1187
|
+
options[:timeout]
|
1164
1188
|
elsif args.last.respond_to?(:to_int)
|
1165
1189
|
# Issue deprecation notice in obnoxious mode...
|
1166
|
-
|
1190
|
+
args.pop.to_int
|
1167
1191
|
end
|
1168
1192
|
|
1193
|
+
timeout ||= 0
|
1194
|
+
|
1169
1195
|
if args.size > 1
|
1170
1196
|
# Issue deprecation notice in obnoxious mode...
|
1171
1197
|
end
|
1172
1198
|
|
1173
1199
|
keys = args.flatten
|
1174
|
-
timeout = options[:timeout] || 0
|
1175
1200
|
|
1176
1201
|
synchronize do |client|
|
1177
1202
|
command = [cmd, keys, timeout]
|
@@ -1196,7 +1221,7 @@ class Redis
|
|
1196
1221
|
# @param [String, Array<String>] keys one or more keys to perform the
|
1197
1222
|
# blocking pop on
|
1198
1223
|
# @param [Hash] options
|
1199
|
-
# - `:timeout =>
|
1224
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1200
1225
|
#
|
1201
1226
|
# @return [nil, [String, String]]
|
1202
1227
|
# - `nil` when the operation timed out
|
@@ -1210,7 +1235,7 @@ class Redis
|
|
1210
1235
|
# @param [String, Array<String>] keys one or more keys to perform the
|
1211
1236
|
# blocking pop on
|
1212
1237
|
# @param [Hash] options
|
1213
|
-
# - `:timeout =>
|
1238
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1214
1239
|
#
|
1215
1240
|
# @return [nil, [String, String]]
|
1216
1241
|
# - `nil` when the operation timed out
|
@@ -1227,20 +1252,12 @@ class Redis
|
|
1227
1252
|
# @param [String] source source key
|
1228
1253
|
# @param [String] destination destination key
|
1229
1254
|
# @param [Hash] options
|
1230
|
-
# - `:timeout =>
|
1255
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1231
1256
|
#
|
1232
1257
|
# @return [nil, String]
|
1233
1258
|
# - `nil` when the operation timed out
|
1234
1259
|
# - the element was popped and pushed otherwise
|
1235
|
-
def brpoplpush(source, destination,
|
1236
|
-
case options
|
1237
|
-
when Integer
|
1238
|
-
# Issue deprecation notice in obnoxious mode...
|
1239
|
-
options = { :timeout => options }
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
timeout = options[:timeout] || 0
|
1243
|
-
|
1260
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
|
1244
1261
|
synchronize do |client|
|
1245
1262
|
command = [:brpoplpush, source, destination, timeout]
|
1246
1263
|
timeout += client.timeout if timeout > 0
|
@@ -1251,7 +1268,7 @@ class Redis
|
|
1251
1268
|
# Get an element from a list by its index.
|
1252
1269
|
#
|
1253
1270
|
# @param [String] key
|
1254
|
-
# @param [
|
1271
|
+
# @param [Integer] index
|
1255
1272
|
# @return [String]
|
1256
1273
|
def lindex(key, index)
|
1257
1274
|
synchronize do |client|
|
@@ -1265,7 +1282,7 @@ class Redis
|
|
1265
1282
|
# @param [String, Symbol] where `BEFORE` or `AFTER`
|
1266
1283
|
# @param [String] pivot reference element
|
1267
1284
|
# @param [String] value
|
1268
|
-
# @return [
|
1285
|
+
# @return [Integer] length of the list after the insert operation, or `-1`
|
1269
1286
|
# when the element `pivot` was not found
|
1270
1287
|
def linsert(key, where, pivot, value)
|
1271
1288
|
synchronize do |client|
|
@@ -1276,8 +1293,8 @@ class Redis
|
|
1276
1293
|
# Get a range of elements from a list.
|
1277
1294
|
#
|
1278
1295
|
# @param [String] key
|
1279
|
-
# @param [
|
1280
|
-
# @param [
|
1296
|
+
# @param [Integer] start start index
|
1297
|
+
# @param [Integer] stop stop index
|
1281
1298
|
# @return [Array<String>]
|
1282
1299
|
def lrange(key, start, stop)
|
1283
1300
|
synchronize do |client|
|
@@ -1288,12 +1305,12 @@ class Redis
|
|
1288
1305
|
# Remove elements from a list.
|
1289
1306
|
#
|
1290
1307
|
# @param [String] key
|
1291
|
-
# @param [
|
1308
|
+
# @param [Integer] count number of elements to remove. Use a positive
|
1292
1309
|
# value to remove the first `count` occurrences of `value`. A negative
|
1293
1310
|
# value to remove the last `count` occurrences of `value`. Or zero, to
|
1294
1311
|
# remove all occurrences of `value` from the list.
|
1295
1312
|
# @param [String] value
|
1296
|
-
# @return [
|
1313
|
+
# @return [Integer] the number of removed elements
|
1297
1314
|
def lrem(key, count, value)
|
1298
1315
|
synchronize do |client|
|
1299
1316
|
client.call([:lrem, key, count, value])
|
@@ -1303,7 +1320,7 @@ class Redis
|
|
1303
1320
|
# Set the value of an element in a list by its index.
|
1304
1321
|
#
|
1305
1322
|
# @param [String] key
|
1306
|
-
# @param [
|
1323
|
+
# @param [Integer] index
|
1307
1324
|
# @param [String] value
|
1308
1325
|
# @return [String] `OK`
|
1309
1326
|
def lset(key, index, value)
|
@@ -1315,8 +1332,8 @@ class Redis
|
|
1315
1332
|
# Trim a list to the specified range.
|
1316
1333
|
#
|
1317
1334
|
# @param [String] key
|
1318
|
-
# @param [
|
1319
|
-
# @param [
|
1335
|
+
# @param [Integer] start start index
|
1336
|
+
# @param [Integer] stop stop index
|
1320
1337
|
# @return [String] `OK`
|
1321
1338
|
def ltrim(key, start, stop)
|
1322
1339
|
synchronize do |client|
|
@@ -1327,7 +1344,7 @@ class Redis
|
|
1327
1344
|
# Get the number of members in a set.
|
1328
1345
|
#
|
1329
1346
|
# @param [String] key
|
1330
|
-
# @return [
|
1347
|
+
# @return [Integer]
|
1331
1348
|
def scard(key)
|
1332
1349
|
synchronize do |client|
|
1333
1350
|
client.call([:scard, key])
|
@@ -1338,8 +1355,8 @@ class Redis
|
|
1338
1355
|
#
|
1339
1356
|
# @param [String] key
|
1340
1357
|
# @param [String, Array<String>] member one member, or array of members
|
1341
|
-
# @return [Boolean,
|
1342
|
-
# holding whether or not adding the member succeeded, or `
|
1358
|
+
# @return [Boolean, Integer] `Boolean` when a single member is specified,
|
1359
|
+
# holding whether or not adding the member succeeded, or `Integer` when an
|
1343
1360
|
# array of members is specified, holding the number of members that were
|
1344
1361
|
# successfully added
|
1345
1362
|
def sadd(key, member)
|
@@ -1360,8 +1377,8 @@ class Redis
|
|
1360
1377
|
#
|
1361
1378
|
# @param [String] key
|
1362
1379
|
# @param [String, Array<String>] member one member, or array of members
|
1363
|
-
# @return [Boolean,
|
1364
|
-
# holding whether or not removing the member succeeded, or `
|
1380
|
+
# @return [Boolean, Integer] `Boolean` when a single member is specified,
|
1381
|
+
# holding whether or not removing the member succeeded, or `Integer` when an
|
1365
1382
|
# array of members is specified, holding the number of members that were
|
1366
1383
|
# successfully removed
|
1367
1384
|
def srem(key, member)
|
@@ -1382,7 +1399,7 @@ class Redis
|
|
1382
1399
|
#
|
1383
1400
|
# @param [String] key
|
1384
1401
|
# @return [String]
|
1385
|
-
# @param [
|
1402
|
+
# @param [Integer] count
|
1386
1403
|
def spop(key, count = nil)
|
1387
1404
|
synchronize do |client|
|
1388
1405
|
if count.nil?
|
@@ -1396,7 +1413,7 @@ class Redis
|
|
1396
1413
|
# Get one or more random members from a set.
|
1397
1414
|
#
|
1398
1415
|
# @param [String] key
|
1399
|
-
# @param [
|
1416
|
+
# @param [Integer] count
|
1400
1417
|
# @return [String]
|
1401
1418
|
def srandmember(key, count = nil)
|
1402
1419
|
synchronize do |client|
|
@@ -1447,7 +1464,7 @@ class Redis
|
|
1447
1464
|
# @return [Array<String>] members in the difference
|
1448
1465
|
def sdiff(*keys)
|
1449
1466
|
synchronize do |client|
|
1450
|
-
client.call([:sdiff
|
1467
|
+
client.call([:sdiff, *keys])
|
1451
1468
|
end
|
1452
1469
|
end
|
1453
1470
|
|
@@ -1455,10 +1472,10 @@ class Redis
|
|
1455
1472
|
#
|
1456
1473
|
# @param [String] destination destination key
|
1457
1474
|
# @param [String, Array<String>] keys keys pointing to sets to subtract
|
1458
|
-
# @return [
|
1475
|
+
# @return [Integer] number of elements in the resulting set
|
1459
1476
|
def sdiffstore(destination, *keys)
|
1460
1477
|
synchronize do |client|
|
1461
|
-
client.call([:sdiffstore, destination
|
1478
|
+
client.call([:sdiffstore, destination, *keys])
|
1462
1479
|
end
|
1463
1480
|
end
|
1464
1481
|
|
@@ -1468,7 +1485,7 @@ class Redis
|
|
1468
1485
|
# @return [Array<String>] members in the intersection
|
1469
1486
|
def sinter(*keys)
|
1470
1487
|
synchronize do |client|
|
1471
|
-
client.call([:sinter
|
1488
|
+
client.call([:sinter, *keys])
|
1472
1489
|
end
|
1473
1490
|
end
|
1474
1491
|
|
@@ -1476,10 +1493,10 @@ class Redis
|
|
1476
1493
|
#
|
1477
1494
|
# @param [String] destination destination key
|
1478
1495
|
# @param [String, Array<String>] keys keys pointing to sets to intersect
|
1479
|
-
# @return [
|
1496
|
+
# @return [Integer] number of elements in the resulting set
|
1480
1497
|
def sinterstore(destination, *keys)
|
1481
1498
|
synchronize do |client|
|
1482
|
-
client.call([:sinterstore, destination
|
1499
|
+
client.call([:sinterstore, destination, *keys])
|
1483
1500
|
end
|
1484
1501
|
end
|
1485
1502
|
|
@@ -1489,7 +1506,7 @@ class Redis
|
|
1489
1506
|
# @return [Array<String>] members in the union
|
1490
1507
|
def sunion(*keys)
|
1491
1508
|
synchronize do |client|
|
1492
|
-
client.call([:sunion
|
1509
|
+
client.call([:sunion, *keys])
|
1493
1510
|
end
|
1494
1511
|
end
|
1495
1512
|
|
@@ -1497,10 +1514,10 @@ class Redis
|
|
1497
1514
|
#
|
1498
1515
|
# @param [String] destination destination key
|
1499
1516
|
# @param [String, Array<String>] keys keys pointing to sets to unify
|
1500
|
-
# @return [
|
1517
|
+
# @return [Integer] number of elements in the resulting set
|
1501
1518
|
def sunionstore(destination, *keys)
|
1502
1519
|
synchronize do |client|
|
1503
|
-
client.call([:sunionstore, destination
|
1520
|
+
client.call([:sunionstore, destination, *keys])
|
1504
1521
|
end
|
1505
1522
|
end
|
1506
1523
|
|
@@ -1511,7 +1528,7 @@ class Redis
|
|
1511
1528
|
# # => 4
|
1512
1529
|
#
|
1513
1530
|
# @param [String] key
|
1514
|
-
# @return [
|
1531
|
+
# @return [Integer]
|
1515
1532
|
def zcard(key)
|
1516
1533
|
synchronize do |client|
|
1517
1534
|
client.call([:zcard, key])
|
@@ -1542,38 +1559,27 @@ class Redis
|
|
1542
1559
|
# - `:incr => true`: When this option is specified ZADD acts like
|
1543
1560
|
# ZINCRBY; only one score-element pair can be specified in this mode
|
1544
1561
|
#
|
1545
|
-
# @return [Boolean,
|
1562
|
+
# @return [Boolean, Integer, Float]
|
1546
1563
|
# - `Boolean` when a single pair is specified, holding whether or not it was
|
1547
1564
|
# **added** to the sorted set.
|
1548
|
-
# - `
|
1565
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
1549
1566
|
# pairs that were **added** to the sorted set.
|
1550
1567
|
# - `Float` when option :incr is specified, holding the score of the member
|
1551
1568
|
# after incrementing it.
|
1552
|
-
def zadd(key, *args
|
1553
|
-
|
1554
|
-
if
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
zadd_options << "NX" if nx
|
1559
|
-
|
1560
|
-
xx = options[:xx]
|
1561
|
-
zadd_options << "XX" if xx
|
1562
|
-
|
1563
|
-
ch = options[:ch]
|
1564
|
-
zadd_options << "CH" if ch
|
1565
|
-
|
1566
|
-
incr = options[:incr]
|
1567
|
-
zadd_options << "INCR" if incr
|
1568
|
-
end
|
1569
|
+
def zadd(key, *args, nx: nil, xx: nil, ch: nil, incr: nil)
|
1570
|
+
command = [:zadd, key]
|
1571
|
+
command << "NX" if nx
|
1572
|
+
command << "XX" if xx
|
1573
|
+
command << "CH" if ch
|
1574
|
+
command << "INCR" if incr
|
1569
1575
|
|
1570
1576
|
synchronize do |client|
|
1571
1577
|
if args.size == 1 && args[0].is_a?(Array)
|
1572
1578
|
# Variadic: return float if INCR, integer if !INCR
|
1573
|
-
client.call(
|
1579
|
+
client.call(command + args[0], &(incr ? Floatify : nil))
|
1574
1580
|
elsif args.size == 2
|
1575
1581
|
# Single pair: return float if INCR, boolean if !INCR
|
1576
|
-
client.call(
|
1582
|
+
client.call(command + args, &(incr ? Floatify : Boolify))
|
1577
1583
|
else
|
1578
1584
|
raise ArgumentError, "wrong number of arguments"
|
1579
1585
|
end
|
@@ -1608,10 +1614,10 @@ class Redis
|
|
1608
1614
|
# - a single member
|
1609
1615
|
# - an array of members
|
1610
1616
|
#
|
1611
|
-
# @return [Boolean,
|
1617
|
+
# @return [Boolean, Integer]
|
1612
1618
|
# - `Boolean` when a single member is specified, holding whether or not it
|
1613
1619
|
# was removed from the sorted set
|
1614
|
-
# - `
|
1620
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
1615
1621
|
# members that were removed to the sorted set
|
1616
1622
|
def zrem(key, member)
|
1617
1623
|
synchronize do |client|
|
@@ -1736,18 +1742,16 @@ class Redis
|
|
1736
1742
|
# # => [["a", 32.0], ["b", 64.0]]
|
1737
1743
|
#
|
1738
1744
|
# @param [String] key
|
1739
|
-
# @param [
|
1740
|
-
# @param [
|
1745
|
+
# @param [Integer] start start index
|
1746
|
+
# @param [Integer] stop stop index
|
1741
1747
|
# @param [Hash] options
|
1742
1748
|
# - `:with_scores => true`: include scores in output
|
1743
1749
|
#
|
1744
1750
|
# @return [Array<String>, Array<[String, Float]>]
|
1745
1751
|
# - when `:with_scores` is not specified, an array of members
|
1746
1752
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1747
|
-
def zrange(key, start, stop,
|
1748
|
-
args = []
|
1749
|
-
|
1750
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1753
|
+
def zrange(key, start, stop, withscores: false, with_scores: withscores)
|
1754
|
+
args = [:zrange, key, start, stop]
|
1751
1755
|
|
1752
1756
|
if with_scores
|
1753
1757
|
args << "WITHSCORES"
|
@@ -1755,7 +1759,7 @@ class Redis
|
|
1755
1759
|
end
|
1756
1760
|
|
1757
1761
|
synchronize do |client|
|
1758
|
-
client.call(
|
1762
|
+
client.call(args, &block)
|
1759
1763
|
end
|
1760
1764
|
end
|
1761
1765
|
|
@@ -1770,10 +1774,8 @@ class Redis
|
|
1770
1774
|
# # => [["b", 64.0], ["a", 32.0]]
|
1771
1775
|
#
|
1772
1776
|
# @see #zrange
|
1773
|
-
def zrevrange(key, start, stop,
|
1774
|
-
args = []
|
1775
|
-
|
1776
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1777
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
1778
|
+
args = [:zrevrange, key, start, stop]
|
1777
1779
|
|
1778
1780
|
if with_scores
|
1779
1781
|
args << "WITHSCORES"
|
@@ -1781,7 +1783,7 @@ class Redis
|
|
1781
1783
|
end
|
1782
1784
|
|
1783
1785
|
synchronize do |client|
|
1784
|
-
client.call(
|
1786
|
+
client.call(args, &block)
|
1785
1787
|
end
|
1786
1788
|
end
|
1787
1789
|
|
@@ -1789,7 +1791,7 @@ class Redis
|
|
1789
1791
|
#
|
1790
1792
|
# @param [String] key
|
1791
1793
|
# @param [String] member
|
1792
|
-
# @return [
|
1794
|
+
# @return [Integer]
|
1793
1795
|
def zrank(key, member)
|
1794
1796
|
synchronize do |client|
|
1795
1797
|
client.call([:zrank, key, member])
|
@@ -1801,7 +1803,7 @@ class Redis
|
|
1801
1803
|
#
|
1802
1804
|
# @param [String] key
|
1803
1805
|
# @param [String] member
|
1804
|
-
# @return [
|
1806
|
+
# @return [Integer]
|
1805
1807
|
def zrevrank(key, member)
|
1806
1808
|
synchronize do |client|
|
1807
1809
|
client.call([:zrevrank, key, member])
|
@@ -1818,9 +1820,9 @@ class Redis
|
|
1818
1820
|
# # => 5
|
1819
1821
|
#
|
1820
1822
|
# @param [String] key
|
1821
|
-
# @param [
|
1822
|
-
# @param [
|
1823
|
-
# @return [
|
1823
|
+
# @param [Integer] start start index
|
1824
|
+
# @param [Integer] stop stop index
|
1825
|
+
# @return [Integer] number of members that were removed
|
1824
1826
|
def zremrangebyrank(key, start, stop)
|
1825
1827
|
synchronize do |client|
|
1826
1828
|
client.call([:zremrangebyrank, key, start, stop])
|
@@ -1844,7 +1846,7 @@ class Redis
|
|
1844
1846
|
# - inclusive maximum is specified by prefixing `(`
|
1845
1847
|
# - exclusive maximum is specified by prefixing `[`
|
1846
1848
|
#
|
1847
|
-
# @return [
|
1849
|
+
# @return [Integer] number of members within the specified lexicographical range
|
1848
1850
|
def zlexcount(key, min, max)
|
1849
1851
|
synchronize do |client|
|
1850
1852
|
client.call([:zlexcount, key, min, max])
|
@@ -1872,14 +1874,16 @@ class Redis
|
|
1872
1874
|
# `count` members
|
1873
1875
|
#
|
1874
1876
|
# @return [Array<String>, Array<[String, Float]>]
|
1875
|
-
def zrangebylex(key, min, max,
|
1876
|
-
args = []
|
1877
|
+
def zrangebylex(key, min, max, limit: nil)
|
1878
|
+
args = [:zrangebylex, key, min, max]
|
1877
1879
|
|
1878
|
-
|
1879
|
-
|
1880
|
+
if limit
|
1881
|
+
args << "LIMIT"
|
1882
|
+
args.concat(limit)
|
1883
|
+
end
|
1880
1884
|
|
1881
1885
|
synchronize do |client|
|
1882
|
-
client.call(
|
1886
|
+
client.call(args)
|
1883
1887
|
end
|
1884
1888
|
end
|
1885
1889
|
|
@@ -1894,14 +1898,16 @@ class Redis
|
|
1894
1898
|
# # => ["abbygail", "abby"]
|
1895
1899
|
#
|
1896
1900
|
# @see #zrangebylex
|
1897
|
-
def zrevrangebylex(key, max, min,
|
1898
|
-
args = []
|
1901
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
1902
|
+
args = [:zrevrangebylex, key, max, min]
|
1899
1903
|
|
1900
|
-
|
1901
|
-
|
1904
|
+
if limit
|
1905
|
+
args << "LIMIT"
|
1906
|
+
args.concat(limit)
|
1907
|
+
end
|
1902
1908
|
|
1903
1909
|
synchronize do |client|
|
1904
|
-
client.call(
|
1910
|
+
client.call(args)
|
1905
1911
|
end
|
1906
1912
|
end
|
1907
1913
|
|
@@ -1932,21 +1938,21 @@ class Redis
|
|
1932
1938
|
# @return [Array<String>, Array<[String, Float]>]
|
1933
1939
|
# - when `:with_scores` is not specified, an array of members
|
1934
1940
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1935
|
-
def zrangebyscore(key, min, max,
|
1936
|
-
args = []
|
1937
|
-
|
1938
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1941
|
+
def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
|
1942
|
+
args = [:zrangebyscore, key, min, max]
|
1939
1943
|
|
1940
1944
|
if with_scores
|
1941
1945
|
args << "WITHSCORES"
|
1942
1946
|
block = FloatifyPairs
|
1943
1947
|
end
|
1944
1948
|
|
1945
|
-
|
1946
|
-
|
1949
|
+
if limit
|
1950
|
+
args << "LIMIT"
|
1951
|
+
args.concat(limit)
|
1952
|
+
end
|
1947
1953
|
|
1948
1954
|
synchronize do |client|
|
1949
|
-
client.call(
|
1955
|
+
client.call(args, &block)
|
1950
1956
|
end
|
1951
1957
|
end
|
1952
1958
|
|
@@ -1964,21 +1970,21 @@ class Redis
|
|
1964
1970
|
# # => [["b", 64.0], ["a", 32.0]]
|
1965
1971
|
#
|
1966
1972
|
# @see #zrangebyscore
|
1967
|
-
def zrevrangebyscore(key, max, min,
|
1968
|
-
args = []
|
1969
|
-
|
1970
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1973
|
+
def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
|
1974
|
+
args = [:zrevrangebyscore, key, max, min]
|
1971
1975
|
|
1972
1976
|
if with_scores
|
1973
|
-
args <<
|
1977
|
+
args << "WITHSCORES"
|
1974
1978
|
block = FloatifyPairs
|
1975
1979
|
end
|
1976
1980
|
|
1977
|
-
|
1978
|
-
|
1981
|
+
if limit
|
1982
|
+
args << "LIMIT"
|
1983
|
+
args.concat(limit)
|
1984
|
+
end
|
1979
1985
|
|
1980
1986
|
synchronize do |client|
|
1981
|
-
client.call(
|
1987
|
+
client.call(args, &block)
|
1982
1988
|
end
|
1983
1989
|
end
|
1984
1990
|
|
@@ -1998,7 +2004,7 @@ class Redis
|
|
1998
2004
|
# @param [String] max
|
1999
2005
|
# - inclusive maximum score is specified verbatim
|
2000
2006
|
# - exclusive maximum score is specified by prefixing `(`
|
2001
|
-
# @return [
|
2007
|
+
# @return [Integer] number of members that were removed
|
2002
2008
|
def zremrangebyscore(key, min, max)
|
2003
2009
|
synchronize do |client|
|
2004
2010
|
client.call([:zremrangebyscore, key, min, max])
|
@@ -2021,7 +2027,7 @@ class Redis
|
|
2021
2027
|
# @param [String] max
|
2022
2028
|
# - inclusive maximum score is specified verbatim
|
2023
2029
|
# - exclusive maximum score is specified by prefixing `(`
|
2024
|
-
# @return [
|
2030
|
+
# @return [Integer] number of members in within the specified range
|
2025
2031
|
def zcount(key, min, max)
|
2026
2032
|
synchronize do |client|
|
2027
2033
|
client.call([:zcount, key, min, max])
|
@@ -2041,18 +2047,19 @@ class Redis
|
|
2041
2047
|
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2042
2048
|
# sorted sets
|
2043
2049
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2044
|
-
# @return [
|
2045
|
-
def zinterstore(destination, keys,
|
2046
|
-
args = []
|
2050
|
+
# @return [Integer] number of elements in the resulting sorted set
|
2051
|
+
def zinterstore(destination, keys, weights: nil, aggregate: nil)
|
2052
|
+
args = [:zinterstore, destination, keys.size, *keys]
|
2047
2053
|
|
2048
|
-
|
2049
|
-
|
2054
|
+
if weights
|
2055
|
+
args << "WEIGHTS"
|
2056
|
+
args.concat(weights)
|
2057
|
+
end
|
2050
2058
|
|
2051
|
-
aggregate
|
2052
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2059
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2053
2060
|
|
2054
2061
|
synchronize do |client|
|
2055
|
-
client.call(
|
2062
|
+
client.call(args)
|
2056
2063
|
end
|
2057
2064
|
end
|
2058
2065
|
|
@@ -2068,40 +2075,46 @@ class Redis
|
|
2068
2075
|
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2069
2076
|
# sorted sets
|
2070
2077
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2071
|
-
# @return [
|
2072
|
-
def zunionstore(destination, keys,
|
2073
|
-
args = []
|
2078
|
+
# @return [Integer] number of elements in the resulting sorted set
|
2079
|
+
def zunionstore(destination, keys, weights: nil, aggregate: nil)
|
2080
|
+
args = [:zunionstore, destination, keys.size, *keys]
|
2074
2081
|
|
2075
|
-
|
2076
|
-
|
2082
|
+
if weights
|
2083
|
+
args << "WEIGHTS"
|
2084
|
+
args.concat(weights)
|
2085
|
+
end
|
2077
2086
|
|
2078
|
-
aggregate
|
2079
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2087
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2080
2088
|
|
2081
2089
|
synchronize do |client|
|
2082
|
-
client.call(
|
2090
|
+
client.call(args)
|
2083
2091
|
end
|
2084
2092
|
end
|
2085
2093
|
|
2086
2094
|
# Get the number of fields in a hash.
|
2087
2095
|
#
|
2088
2096
|
# @param [String] key
|
2089
|
-
# @return [
|
2097
|
+
# @return [Integer] number of fields in the hash
|
2090
2098
|
def hlen(key)
|
2091
2099
|
synchronize do |client|
|
2092
2100
|
client.call([:hlen, key])
|
2093
2101
|
end
|
2094
2102
|
end
|
2095
2103
|
|
2096
|
-
# Set
|
2104
|
+
# Set one or more hash values.
|
2105
|
+
#
|
2106
|
+
# @example
|
2107
|
+
# redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
|
2108
|
+
# redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
|
2097
2109
|
#
|
2098
2110
|
# @param [String] key
|
2099
|
-
# @param [String]
|
2100
|
-
# @
|
2101
|
-
|
2102
|
-
|
2111
|
+
# @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
|
2112
|
+
# @return [Integer] The number of fields that were added to the hash
|
2113
|
+
def hset(key, *attrs)
|
2114
|
+
attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
|
2115
|
+
|
2103
2116
|
synchronize do |client|
|
2104
|
-
client.call([:hset, key,
|
2117
|
+
client.call([:hset, key, *attrs])
|
2105
2118
|
end
|
2106
2119
|
end
|
2107
2120
|
|
@@ -2190,7 +2203,7 @@ class Redis
|
|
2190
2203
|
# @see #hmget
|
2191
2204
|
def mapped_hmget(key, *fields)
|
2192
2205
|
hmget(key, *fields) do |reply|
|
2193
|
-
if reply.
|
2206
|
+
if reply.is_a?(Array)
|
2194
2207
|
Hash[fields.zip(reply)]
|
2195
2208
|
else
|
2196
2209
|
reply
|
@@ -2202,7 +2215,7 @@ class Redis
|
|
2202
2215
|
#
|
2203
2216
|
# @param [String] key
|
2204
2217
|
# @param [String, Array<String>] field
|
2205
|
-
# @return [
|
2218
|
+
# @return [Integer] the number of fields that were removed from the hash
|
2206
2219
|
def hdel(key, *fields)
|
2207
2220
|
synchronize do |client|
|
2208
2221
|
client.call([:hdel, key, *fields])
|
@@ -2224,8 +2237,8 @@ class Redis
|
|
2224
2237
|
#
|
2225
2238
|
# @param [String] key
|
2226
2239
|
# @param [String] field
|
2227
|
-
# @param [
|
2228
|
-
# @return [
|
2240
|
+
# @param [Integer] increment
|
2241
|
+
# @return [Integer] value of the field after incrementing it
|
2229
2242
|
def hincrby(key, field, increment)
|
2230
2243
|
synchronize do |client|
|
2231
2244
|
client.call([:hincrby, key, field, increment])
|
@@ -2283,20 +2296,21 @@ class Redis
|
|
2283
2296
|
|
2284
2297
|
def subscribed?
|
2285
2298
|
synchronize do |client|
|
2286
|
-
client.
|
2299
|
+
client.is_a? SubscribedClient
|
2287
2300
|
end
|
2288
2301
|
end
|
2289
2302
|
|
2290
2303
|
# Listen for messages published to the given channels.
|
2291
2304
|
def subscribe(*channels, &block)
|
2292
|
-
synchronize do |
|
2305
|
+
synchronize do |_client|
|
2293
2306
|
_subscription(:subscribe, 0, channels, block)
|
2294
2307
|
end
|
2295
2308
|
end
|
2296
2309
|
|
2297
|
-
# Listen for messages published to the given channels. Throw a timeout error
|
2310
|
+
# Listen for messages published to the given channels. Throw a timeout error
|
2311
|
+
# if there is no messages for a timeout period.
|
2298
2312
|
def subscribe_with_timeout(timeout, *channels, &block)
|
2299
|
-
synchronize do |
|
2313
|
+
synchronize do |_client|
|
2300
2314
|
_subscription(:subscribe_with_timeout, timeout, channels, block)
|
2301
2315
|
end
|
2302
2316
|
end
|
@@ -2304,21 +2318,23 @@ class Redis
|
|
2304
2318
|
# Stop listening for messages posted to the given channels.
|
2305
2319
|
def unsubscribe(*channels)
|
2306
2320
|
synchronize do |client|
|
2307
|
-
raise
|
2321
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2322
|
+
|
2308
2323
|
client.unsubscribe(*channels)
|
2309
2324
|
end
|
2310
2325
|
end
|
2311
2326
|
|
2312
2327
|
# Listen for messages published to channels matching the given patterns.
|
2313
2328
|
def psubscribe(*channels, &block)
|
2314
|
-
synchronize do |
|
2329
|
+
synchronize do |_client|
|
2315
2330
|
_subscription(:psubscribe, 0, channels, block)
|
2316
2331
|
end
|
2317
2332
|
end
|
2318
2333
|
|
2319
|
-
# Listen for messages published to channels matching the given patterns.
|
2334
|
+
# Listen for messages published to channels matching the given patterns.
|
2335
|
+
# Throw a timeout error if there is no messages for a timeout period.
|
2320
2336
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
2321
|
-
synchronize do |
|
2337
|
+
synchronize do |_client|
|
2322
2338
|
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
2323
2339
|
end
|
2324
2340
|
end
|
@@ -2326,7 +2342,8 @@ class Redis
|
|
2326
2342
|
# Stop listening for messages posted to channels matching the given patterns.
|
2327
2343
|
def punsubscribe(*channels)
|
2328
2344
|
synchronize do |client|
|
2329
|
-
raise
|
2345
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2346
|
+
|
2330
2347
|
client.punsubscribe(*channels)
|
2331
2348
|
end
|
2332
2349
|
end
|
@@ -2371,7 +2388,7 @@ class Redis
|
|
2371
2388
|
# @see #multi
|
2372
2389
|
def watch(*keys)
|
2373
2390
|
synchronize do |client|
|
2374
|
-
res = client.call([:watch
|
2391
|
+
res = client.call([:watch, *keys])
|
2375
2392
|
|
2376
2393
|
if block_given?
|
2377
2394
|
begin
|
@@ -2401,9 +2418,10 @@ class Redis
|
|
2401
2418
|
end
|
2402
2419
|
|
2403
2420
|
def pipelined
|
2404
|
-
synchronize do |
|
2421
|
+
synchronize do |_client|
|
2405
2422
|
begin
|
2406
|
-
|
2423
|
+
pipeline = Pipeline.new(@client)
|
2424
|
+
original, @client = @client, pipeline
|
2407
2425
|
yield(self)
|
2408
2426
|
original.call_pipeline(@client)
|
2409
2427
|
ensure
|
@@ -2448,7 +2466,7 @@ class Redis
|
|
2448
2466
|
client.call([:multi])
|
2449
2467
|
else
|
2450
2468
|
begin
|
2451
|
-
pipeline = Pipeline::Multi.new
|
2469
|
+
pipeline = Pipeline::Multi.new(@client)
|
2452
2470
|
original, @client = @client, pipeline
|
2453
2471
|
yield(self)
|
2454
2472
|
original.call_pipeline(pipeline)
|
@@ -2600,18 +2618,12 @@ class Redis
|
|
2600
2618
|
_eval(:evalsha, args)
|
2601
2619
|
end
|
2602
2620
|
|
2603
|
-
def _scan(command, cursor, args,
|
2621
|
+
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2604
2622
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2605
2623
|
|
2606
2624
|
args << cursor
|
2607
|
-
|
2608
|
-
|
2609
|
-
args.concat(["MATCH", match])
|
2610
|
-
end
|
2611
|
-
|
2612
|
-
if count = options[:count]
|
2613
|
-
args.concat(["COUNT", count])
|
2614
|
-
end
|
2625
|
+
args << "MATCH" << match if match
|
2626
|
+
args << "COUNT" << count if count
|
2615
2627
|
|
2616
2628
|
synchronize do |client|
|
2617
2629
|
client.call([command] + args, &block)
|
@@ -2633,8 +2645,8 @@ class Redis
|
|
2633
2645
|
# - `:count => Integer`: return count keys at most per iteration
|
2634
2646
|
#
|
2635
2647
|
# @return [String, Array<String>] the next cursor and all found keys
|
2636
|
-
def scan(cursor, options
|
2637
|
-
_scan(:scan, cursor, [], options)
|
2648
|
+
def scan(cursor, **options)
|
2649
|
+
_scan(:scan, cursor, [], **options)
|
2638
2650
|
end
|
2639
2651
|
|
2640
2652
|
# Scan the keyspace
|
@@ -2652,11 +2664,12 @@ class Redis
|
|
2652
2664
|
# - `:count => Integer`: return count keys at most per iteration
|
2653
2665
|
#
|
2654
2666
|
# @return [Enumerator] an enumerator for all found keys
|
2655
|
-
def scan_each(options
|
2656
|
-
return to_enum(:scan_each, options) unless block_given?
|
2667
|
+
def scan_each(**options, &block)
|
2668
|
+
return to_enum(:scan_each, **options) unless block_given?
|
2669
|
+
|
2657
2670
|
cursor = 0
|
2658
2671
|
loop do
|
2659
|
-
cursor, keys = scan(cursor, options)
|
2672
|
+
cursor, keys = scan(cursor, **options)
|
2660
2673
|
keys.each(&block)
|
2661
2674
|
break if cursor == "0"
|
2662
2675
|
end
|
@@ -2673,8 +2686,8 @@ class Redis
|
|
2673
2686
|
# - `:count => Integer`: return count keys at most per iteration
|
2674
2687
|
#
|
2675
2688
|
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
2676
|
-
def hscan(key, cursor, options
|
2677
|
-
_scan(:hscan, cursor, [key], options) do |reply|
|
2689
|
+
def hscan(key, cursor, **options)
|
2690
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2678
2691
|
[reply[0], reply[1].each_slice(2).to_a]
|
2679
2692
|
end
|
2680
2693
|
end
|
@@ -2690,11 +2703,12 @@ class Redis
|
|
2690
2703
|
# - `:count => Integer`: return count keys at most per iteration
|
2691
2704
|
#
|
2692
2705
|
# @return [Enumerator] an enumerator for all found keys
|
2693
|
-
def hscan_each(key, options
|
2694
|
-
return to_enum(:hscan_each, key, options) unless block_given?
|
2706
|
+
def hscan_each(key, **options, &block)
|
2707
|
+
return to_enum(:hscan_each, key, **options) unless block_given?
|
2708
|
+
|
2695
2709
|
cursor = 0
|
2696
2710
|
loop do
|
2697
|
-
cursor, values = hscan(key, cursor, options)
|
2711
|
+
cursor, values = hscan(key, cursor, **options)
|
2698
2712
|
values.each(&block)
|
2699
2713
|
break if cursor == "0"
|
2700
2714
|
end
|
@@ -2712,8 +2726,8 @@ class Redis
|
|
2712
2726
|
#
|
2713
2727
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2714
2728
|
# members and scores
|
2715
|
-
def zscan(key, cursor, options
|
2716
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2729
|
+
def zscan(key, cursor, **options)
|
2730
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2717
2731
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2718
2732
|
end
|
2719
2733
|
end
|
@@ -2729,11 +2743,12 @@ class Redis
|
|
2729
2743
|
# - `:count => Integer`: return count keys at most per iteration
|
2730
2744
|
#
|
2731
2745
|
# @return [Enumerator] an enumerator for all found scores and members
|
2732
|
-
def zscan_each(key, options
|
2733
|
-
return to_enum(:zscan_each, key, options) unless block_given?
|
2746
|
+
def zscan_each(key, **options, &block)
|
2747
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
2748
|
+
|
2734
2749
|
cursor = 0
|
2735
2750
|
loop do
|
2736
|
-
cursor, values = zscan(key, cursor, options)
|
2751
|
+
cursor, values = zscan(key, cursor, **options)
|
2737
2752
|
values.each(&block)
|
2738
2753
|
break if cursor == "0"
|
2739
2754
|
end
|
@@ -2750,8 +2765,8 @@ class Redis
|
|
2750
2765
|
# - `:count => Integer`: return count keys at most per iteration
|
2751
2766
|
#
|
2752
2767
|
# @return [String, Array<String>] the next cursor and all found members
|
2753
|
-
def sscan(key, cursor, options
|
2754
|
-
_scan(:sscan, cursor, [key], options)
|
2768
|
+
def sscan(key, cursor, **options)
|
2769
|
+
_scan(:sscan, cursor, [key], **options)
|
2755
2770
|
end
|
2756
2771
|
|
2757
2772
|
# Scan a set
|
@@ -2765,11 +2780,12 @@ class Redis
|
|
2765
2780
|
# - `:count => Integer`: return count keys at most per iteration
|
2766
2781
|
#
|
2767
2782
|
# @return [Enumerator] an enumerator for all keys in the set
|
2768
|
-
def sscan_each(key, options
|
2769
|
-
return to_enum(:sscan_each, key, options) unless block_given?
|
2783
|
+
def sscan_each(key, **options, &block)
|
2784
|
+
return to_enum(:sscan_each, key, **options) unless block_given?
|
2785
|
+
|
2770
2786
|
cursor = 0
|
2771
2787
|
loop do
|
2772
|
-
cursor, keys = sscan(key, cursor, options)
|
2788
|
+
cursor, keys = sscan(key, cursor, **options)
|
2773
2789
|
keys.each(&block)
|
2774
2790
|
break if cursor == "0"
|
2775
2791
|
end
|
@@ -2792,7 +2808,7 @@ class Redis
|
|
2792
2808
|
# union of the HyperLogLogs contained in the keys.
|
2793
2809
|
#
|
2794
2810
|
# @param [String, Array<String>] keys
|
2795
|
-
# @return [
|
2811
|
+
# @return [Integer]
|
2796
2812
|
def pfcount(*keys)
|
2797
2813
|
synchronize do |client|
|
2798
2814
|
client.call([:pfcount] + keys)
|
@@ -2815,10 +2831,10 @@ class Redis
|
|
2815
2831
|
#
|
2816
2832
|
# @param [String] key
|
2817
2833
|
# @param [Array] member arguemnts for member or members: longitude, latitude, name
|
2818
|
-
# @return [
|
2834
|
+
# @return [Integer] number of elements added to the sorted set
|
2819
2835
|
def geoadd(key, *member)
|
2820
2836
|
synchronize do |client|
|
2821
|
-
client.call([:geoadd, key, member])
|
2837
|
+
client.call([:geoadd, key, *member])
|
2822
2838
|
end
|
2823
2839
|
end
|
2824
2840
|
|
@@ -2833,12 +2849,12 @@ class Redis
|
|
2833
2849
|
end
|
2834
2850
|
end
|
2835
2851
|
|
2836
|
-
|
2837
2852
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2838
2853
|
# given maximum distance from a point
|
2839
2854
|
#
|
2840
2855
|
# @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
|
2841
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2856
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2857
|
+
# or the farthest to the nearest relative to the center
|
2842
2858
|
# @param [Integer] count limit the results to the first N matching items
|
2843
2859
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2844
2860
|
# @return [Array<String>] may be changed with `options`
|
@@ -2855,7 +2871,8 @@ class Redis
|
|
2855
2871
|
# given maximum distance from an already existing member
|
2856
2872
|
#
|
2857
2873
|
# @param [Array] args key, member, radius, unit(m|km|ft|mi)
|
2858
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2874
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2875
|
+
# to the nearest relative to the center
|
2859
2876
|
# @param [Integer] count limit the results to the first N matching items
|
2860
2877
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2861
2878
|
# @return [Array<String>] may be changed with `options`
|
@@ -2872,7 +2889,8 @@ class Redis
|
|
2872
2889
|
#
|
2873
2890
|
# @param [String] key
|
2874
2891
|
# @param [String, Array<String>] member one member or array of members
|
2875
|
-
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2892
|
+
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2893
|
+
# element is either array of longitude and latitude or nil
|
2876
2894
|
def geopos(key, member)
|
2877
2895
|
synchronize do |client|
|
2878
2896
|
client.call([:geopos, key, member])
|
@@ -2936,10 +2954,14 @@ class Redis
|
|
2936
2954
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2937
2955
|
#
|
2938
2956
|
# @return [String] the entry id
|
2939
|
-
def xadd(key, entry,
|
2957
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2940
2958
|
args = [:xadd, key]
|
2941
|
-
|
2942
|
-
|
2959
|
+
if maxlen
|
2960
|
+
args << "MAXLEN"
|
2961
|
+
args << "~" if approximate
|
2962
|
+
args << maxlen
|
2963
|
+
end
|
2964
|
+
args << id
|
2943
2965
|
args.concat(entry.to_a.flatten)
|
2944
2966
|
synchronize { |client| client.call(args) }
|
2945
2967
|
end
|
@@ -2977,24 +2999,6 @@ class Redis
|
|
2977
2999
|
synchronize { |client| client.call(args) }
|
2978
3000
|
end
|
2979
3001
|
|
2980
|
-
# Fetches entries of the stream.
|
2981
|
-
#
|
2982
|
-
# @example Without options
|
2983
|
-
# redis.xrange('mystream')
|
2984
|
-
# @example With first entry id option
|
2985
|
-
# redis.xrange('mystream', first: '0-1')
|
2986
|
-
# @example With first and last entry id options
|
2987
|
-
# redis.xrange('mystream', first: '0-1', last: '0-3')
|
2988
|
-
# @example With count options
|
2989
|
-
# redis.xrange('mystream', count: 10)
|
2990
|
-
#
|
2991
|
-
# @param key [String] the stream key
|
2992
|
-
# @param start [String] first entry id of range, default value is `+`
|
2993
|
-
# @param end [String] last entry id of range, default value is `-`
|
2994
|
-
# @param count [Integer] the number of entries as limit
|
2995
|
-
#
|
2996
|
-
# @return [Hash{String => Hash}] the entries
|
2997
|
-
|
2998
3002
|
# Fetches entries of the stream in ascending order.
|
2999
3003
|
#
|
3000
3004
|
# @example Without options
|
@@ -3012,8 +3016,8 @@ class Redis
|
|
3012
3016
|
# @param count [Integer] the number of entries as limit
|
3013
3017
|
#
|
3014
3018
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3015
|
-
def xrange(key, start = '-',
|
3016
|
-
args = [:xrange, key, start,
|
3019
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3020
|
+
args = [:xrange, key, start, range_end]
|
3017
3021
|
args.concat(['COUNT', count]) if count
|
3018
3022
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3019
3023
|
end
|
@@ -3035,8 +3039,8 @@ class Redis
|
|
3035
3039
|
# @params count [Integer] the number of entries as limit
|
3036
3040
|
#
|
3037
3041
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3038
|
-
def xrevrange(key,
|
3039
|
-
args = [:xrevrange, key,
|
3042
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3043
|
+
args = [:xrevrange, key, range_end, start]
|
3040
3044
|
args.concat(['COUNT', count]) if count
|
3041
3045
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3042
3046
|
end
|
@@ -3128,12 +3132,12 @@ class Redis
|
|
3128
3132
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3129
3133
|
#
|
3130
3134
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3131
|
-
def xreadgroup(group, consumer, keys, ids,
|
3135
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3132
3136
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3133
|
-
args << 'COUNT' <<
|
3134
|
-
args << 'BLOCK' <<
|
3135
|
-
args << 'NOACK' if
|
3136
|
-
_xread(args, keys, ids,
|
3137
|
+
args << 'COUNT' << count if count
|
3138
|
+
args << 'BLOCK' << block.to_i if block
|
3139
|
+
args << 'NOACK' if noack
|
3140
|
+
_xread(args, keys, ids, block)
|
3137
3141
|
end
|
3138
3142
|
|
3139
3143
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3243,8 +3247,8 @@ class Redis
|
|
3243
3247
|
when "get-master-addr-by-name"
|
3244
3248
|
reply
|
3245
3249
|
else
|
3246
|
-
if reply.
|
3247
|
-
if reply[0].
|
3250
|
+
if reply.is_a?(Array)
|
3251
|
+
if reply[0].is_a?(Array)
|
3248
3252
|
reply.map(&Hashify)
|
3249
3253
|
else
|
3250
3254
|
Hashify.call(reply)
|
@@ -3268,12 +3272,17 @@ class Redis
|
|
3268
3272
|
def cluster(subcommand, *args)
|
3269
3273
|
subcommand = subcommand.to_s.downcase
|
3270
3274
|
block = case subcommand
|
3271
|
-
|
3272
|
-
|
3273
|
-
|
3274
|
-
|
3275
|
-
|
3276
|
-
|
3275
|
+
when 'slots'
|
3276
|
+
HashifyClusterSlots
|
3277
|
+
when 'nodes'
|
3278
|
+
HashifyClusterNodes
|
3279
|
+
when 'slaves'
|
3280
|
+
HashifyClusterSlaves
|
3281
|
+
when 'info'
|
3282
|
+
HashifyInfo
|
3283
|
+
else
|
3284
|
+
Noop
|
3285
|
+
end
|
3277
3286
|
|
3278
3287
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3279
3288
|
block = Noop unless @cluster_mode
|
@@ -3308,150 +3317,154 @@ class Redis
|
|
3308
3317
|
return @original_client.connection_info if @cluster_mode
|
3309
3318
|
|
3310
3319
|
{
|
3311
|
-
host:
|
3312
|
-
port:
|
3313
|
-
db:
|
3314
|
-
id:
|
3320
|
+
host: @original_client.host,
|
3321
|
+
port: @original_client.port,
|
3322
|
+
db: @original_client.db,
|
3323
|
+
id: @original_client.id,
|
3315
3324
|
location: @original_client.location
|
3316
3325
|
}
|
3317
3326
|
end
|
3318
3327
|
|
3319
|
-
def method_missing(command, *args)
|
3328
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3320
3329
|
synchronize do |client|
|
3321
3330
|
client.call([command] + args)
|
3322
3331
|
end
|
3323
3332
|
end
|
3324
3333
|
|
3325
|
-
private
|
3334
|
+
private
|
3326
3335
|
|
3327
3336
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3328
3337
|
# where the method call will return nil. Propagate the nil instead of falsely
|
3329
3338
|
# returning false.
|
3330
|
-
Boolify =
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3339
|
+
Boolify = lambda { |value|
|
3340
|
+
case value
|
3341
|
+
when 1
|
3342
|
+
true
|
3343
|
+
when 0
|
3344
|
+
false
|
3345
|
+
else
|
3346
|
+
value
|
3347
|
+
end
|
3348
|
+
}
|
3334
3349
|
|
3335
|
-
BoolifySet =
|
3336
|
-
|
3337
|
-
|
3338
|
-
|
3339
|
-
|
3340
|
-
|
3341
|
-
|
3342
|
-
|
3350
|
+
BoolifySet = lambda { |value|
|
3351
|
+
case value
|
3352
|
+
when "OK"
|
3353
|
+
true
|
3354
|
+
when nil
|
3355
|
+
false
|
3356
|
+
else
|
3357
|
+
value
|
3358
|
+
end
|
3359
|
+
}
|
3343
3360
|
|
3344
|
-
Hashify =
|
3345
|
-
|
3346
|
-
|
3347
|
-
|
3348
|
-
|
3349
|
-
|
3350
|
-
|
3351
|
-
|
3361
|
+
Hashify = lambda { |value|
|
3362
|
+
if value.respond_to?(:each_slice)
|
3363
|
+
value.each_slice(2).to_h
|
3364
|
+
else
|
3365
|
+
value
|
3366
|
+
end
|
3367
|
+
}
|
3368
|
+
|
3369
|
+
Floatify = lambda { |value|
|
3370
|
+
case value
|
3371
|
+
when "inf"
|
3372
|
+
Float::INFINITY
|
3373
|
+
when "-inf"
|
3374
|
+
-Float::INFINITY
|
3375
|
+
when String
|
3376
|
+
Float(value)
|
3377
|
+
else
|
3378
|
+
value
|
3379
|
+
end
|
3380
|
+
}
|
3352
3381
|
|
3353
|
-
|
3354
|
-
|
3355
|
-
if str
|
3356
|
-
if (inf = str.match(/^(-)?inf/i))
|
3357
|
-
(inf[1] ? -1.0 : 1.0) / 0.0
|
3358
|
-
else
|
3359
|
-
Float(str)
|
3360
|
-
end
|
3361
|
-
end
|
3362
|
-
}
|
3382
|
+
FloatifyPairs = lambda { |value|
|
3383
|
+
return value unless value.respond_to?(:each_slice)
|
3363
3384
|
|
3364
|
-
|
3365
|
-
|
3366
|
-
|
3367
|
-
|
3368
|
-
end
|
3369
|
-
}
|
3385
|
+
value.each_slice(2).map do |member, score|
|
3386
|
+
[member, Floatify.call(score)]
|
3387
|
+
end
|
3388
|
+
}
|
3370
3389
|
|
3371
|
-
HashifyInfo =
|
3372
|
-
|
3373
|
-
|
3374
|
-
|
3375
|
-
|
3376
|
-
|
3390
|
+
HashifyInfo = lambda { |reply|
|
3391
|
+
lines = reply.split("\r\n").grep_v(/^(#|$)/)
|
3392
|
+
lines.map! { |line| line.split(':', 2) }
|
3393
|
+
lines.compact!
|
3394
|
+
lines.to_h
|
3395
|
+
}
|
3377
3396
|
|
3378
|
-
HashifyStreams =
|
3379
|
-
|
3380
|
-
|
3381
|
-
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3397
|
+
HashifyStreams = lambda { |reply|
|
3398
|
+
case reply
|
3399
|
+
when nil
|
3400
|
+
{}
|
3401
|
+
else
|
3402
|
+
reply.map { |key, entries| [key, HashifyStreamEntries.call(entries)] }.to_h
|
3403
|
+
end
|
3404
|
+
}
|
3385
3405
|
|
3386
|
-
HashifyStreamEntries =
|
3387
|
-
|
3388
|
-
|
3389
|
-
|
3390
|
-
|
3406
|
+
HashifyStreamEntries = lambda { |reply|
|
3407
|
+
reply.map do |entry_id, values|
|
3408
|
+
[entry_id, values.each_slice(2).to_h]
|
3409
|
+
end
|
3410
|
+
}
|
3411
|
+
|
3412
|
+
HashifyStreamPendings = lambda { |reply|
|
3413
|
+
{
|
3414
|
+
'size' => reply[0],
|
3415
|
+
'min_entry_id' => reply[1],
|
3416
|
+
'max_entry_id' => reply[2],
|
3417
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3391
3418
|
}
|
3419
|
+
}
|
3392
3420
|
|
3393
|
-
|
3394
|
-
|
3421
|
+
HashifyStreamPendingDetails = lambda { |reply|
|
3422
|
+
reply.map do |arr|
|
3395
3423
|
{
|
3396
|
-
'
|
3397
|
-
'
|
3398
|
-
'
|
3399
|
-
'
|
3424
|
+
'entry_id' => arr[0],
|
3425
|
+
'consumer' => arr[1],
|
3426
|
+
'elapsed' => arr[2],
|
3427
|
+
'count' => arr[3]
|
3400
3428
|
}
|
3401
|
-
|
3429
|
+
end
|
3430
|
+
}
|
3402
3431
|
|
3403
|
-
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3407
|
-
|
3408
|
-
|
3409
|
-
|
3410
|
-
|
3411
|
-
|
3412
|
-
|
3432
|
+
HashifyClusterNodeInfo = lambda { |str|
|
3433
|
+
arr = str.split(' ')
|
3434
|
+
{
|
3435
|
+
'node_id' => arr[0],
|
3436
|
+
'ip_port' => arr[1],
|
3437
|
+
'flags' => arr[2].split(','),
|
3438
|
+
'master_node_id' => arr[3],
|
3439
|
+
'ping_sent' => arr[4],
|
3440
|
+
'pong_recv' => arr[5],
|
3441
|
+
'config_epoch' => arr[6],
|
3442
|
+
'link_state' => arr[7],
|
3443
|
+
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3413
3444
|
}
|
3445
|
+
}
|
3414
3446
|
|
3415
|
-
|
3416
|
-
|
3417
|
-
|
3447
|
+
HashifyClusterSlots = lambda { |reply|
|
3448
|
+
reply.map do |arr|
|
3449
|
+
first_slot, last_slot = arr[0..1]
|
3450
|
+
master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
|
3451
|
+
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3418
3452
|
{
|
3419
|
-
'
|
3420
|
-
'
|
3421
|
-
'
|
3422
|
-
'
|
3423
|
-
'ping_sent' => arr[4],
|
3424
|
-
'pong_recv' => arr[5],
|
3425
|
-
'config_epoch' => arr[6],
|
3426
|
-
'link_state' => arr[7],
|
3427
|
-
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3453
|
+
'start_slot' => first_slot,
|
3454
|
+
'end_slot' => last_slot,
|
3455
|
+
'master' => master,
|
3456
|
+
'replicas' => replicas
|
3428
3457
|
}
|
3429
|
-
|
3430
|
-
|
3431
|
-
HashifyClusterSlots =
|
3432
|
-
lambda { |reply|
|
3433
|
-
reply.map do |arr|
|
3434
|
-
first_slot, last_slot = arr[0..1]
|
3435
|
-
master = { 'ip' => arr[2][0], 'port' => arr[2][1], 'node_id' => arr[2][2] }
|
3436
|
-
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3437
|
-
{
|
3438
|
-
'start_slot' => first_slot,
|
3439
|
-
'end_slot' => last_slot,
|
3440
|
-
'master' => master,
|
3441
|
-
'replicas' => replicas
|
3442
|
-
}
|
3443
|
-
end
|
3444
|
-
}
|
3458
|
+
end
|
3459
|
+
}
|
3445
3460
|
|
3446
|
-
HashifyClusterNodes =
|
3447
|
-
|
3448
|
-
|
3449
|
-
}
|
3461
|
+
HashifyClusterNodes = lambda { |reply|
|
3462
|
+
reply.split(/[\r\n]+/).map { |str| HashifyClusterNodeInfo.call(str) }
|
3463
|
+
}
|
3450
3464
|
|
3451
|
-
HashifyClusterSlaves =
|
3452
|
-
|
3453
|
-
|
3454
|
-
}
|
3465
|
+
HashifyClusterSlaves = lambda { |reply|
|
3466
|
+
reply.map { |str| HashifyClusterNodeInfo.call(str) }
|
3467
|
+
}
|
3455
3468
|
|
3456
3469
|
Noop = ->(reply) { reply }
|
3457
3470
|
|
@@ -3459,8 +3472,7 @@ private
|
|
3459
3472
|
args.push sort if sort
|
3460
3473
|
args.push 'count', count if count
|
3461
3474
|
args.push options if options
|
3462
|
-
|
3463
|
-
args.uniq
|
3475
|
+
args
|
3464
3476
|
end
|
3465
3477
|
|
3466
3478
|
def _subscription(method, timeout, channels, block)
|
@@ -3488,6 +3500,8 @@ private
|
|
3488
3500
|
synchronize do |client|
|
3489
3501
|
if blocking_timeout_msec.nil?
|
3490
3502
|
client.call(args, &HashifyStreams)
|
3503
|
+
elsif blocking_timeout_msec.to_f.zero?
|
3504
|
+
client.call_without_timeout(args, &HashifyStreams)
|
3491
3505
|
else
|
3492
3506
|
timeout = client.timeout.to_f + blocking_timeout_msec.to_f / 1000.0
|
3493
3507
|
client.call_with_timeout(args, timeout, &HashifyStreams)
|