redis 4.1.2 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -1
- data/README.md +14 -5
- data/lib/redis.rb +385 -343
- data/lib/redis/client.rb +66 -69
- 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 +47 -58
- data/lib/redis/connection/synchrony.rb +9 -4
- data/lib/redis/distributed.rb +117 -62
- data/lib/redis/errors.rb +2 -0
- data/lib/redis/hash_ring.rb +15 -14
- data/lib/redis/pipeline.rb +16 -3
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- metadata +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28eb23d20152436fc47f334f517c6fa62855e8e4711b44979cb05d86f8dcdd34
|
4
|
+
data.tar.gz: 46d01b3f5539800142582aeb7ebeabe4327bce970e31ce2048dcba027dfe6eb1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2f11269c6a3a030231eeb93dfa6bee54b340ff5ad244df6d79074c95f111e3d2081f49f77756576cb8225640e8b8cad144884c8519bcf1b0e7bedea3ca1b00f
|
7
|
+
data.tar.gz: 44ec06531632060b497cf1d02e6678c3d087ec3371cba86f53f9687848f73bb4e02c166b11d4db9e6b531b62ba2ca830649d71114063560f6dd764ca2ef10f07
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,46 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
-
# 4.
|
3
|
+
# 4.2.2
|
4
|
+
|
5
|
+
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
6
|
+
* Fix handling of empty stream responses. See #905, #929.
|
7
|
+
|
8
|
+
# 4.2.1
|
9
|
+
|
10
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
11
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
12
|
+
|
13
|
+
# 4.2.0
|
14
|
+
|
15
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
16
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
17
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
18
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
19
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
20
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
21
|
+
* Support `keepttl` ooption in `set`. See #913.
|
22
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
23
|
+
* Accept sentinel options even with string key. See #599.
|
24
|
+
* Verify TLS connections by default. See #900.
|
25
|
+
* Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
|
26
|
+
|
27
|
+
# 4.1.4
|
28
|
+
|
29
|
+
* Alias `Redis#disconnect` as `#close`. See #901.
|
30
|
+
* Handle clusters with multiple slot ranges. See #894.
|
31
|
+
* Fix password authentication to a redis cluster. See #889.
|
32
|
+
* Handle recursive MOVED responses. See #882.
|
33
|
+
* Increase buffer size in the ruby connector. See #880.
|
34
|
+
* Fix thread safety of `Redis.queue`. See #878.
|
35
|
+
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
36
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
37
|
+
|
38
|
+
# 4.1.3
|
4
39
|
|
5
40
|
* Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
|
41
|
+
|
42
|
+
# 4.1.2
|
43
|
+
|
6
44
|
* Fix several authentication problems with sentinel. See #850 and #856.
|
7
45
|
* Explicitly drop Ruby 2.2 support.
|
8
46
|
|
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.
|
@@ -142,12 +146,13 @@ redis.mget('{key}1', '{key}2')
|
|
142
146
|
```
|
143
147
|
|
144
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.
|
145
150
|
* The client supports `MOVED` and `ASK` redirections transparently.
|
146
151
|
|
147
152
|
## Storing objects
|
148
153
|
|
149
|
-
Redis
|
150
|
-
|
154
|
+
Redis "string" types can be used to store serialized Ruby objects, for
|
155
|
+
example with JSON:
|
151
156
|
|
152
157
|
```ruby
|
153
158
|
require "json"
|
@@ -321,7 +326,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
321
326
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
322
327
|
or [ghostunnel].
|
323
328
|
|
324
|
-
To enable SSL support, pass the `:ssl =>
|
329
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
325
330
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
326
331
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
327
332
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -436,6 +441,10 @@ redis = Redis.new(:driver => :synchrony)
|
|
436
441
|
This library is tested against recent Ruby and Redis versions.
|
437
442
|
Check [Travis][travis-link] for the exact versions supported.
|
438
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
|
+
|
439
448
|
## Contributors
|
440
449
|
|
441
450
|
Several people contributed to redis-rb, but we would like to especially
|
@@ -446,7 +455,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
446
455
|
## Contributing
|
447
456
|
|
448
457
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
449
|
-
requests.
|
458
|
+
requests.
|
450
459
|
|
451
460
|
|
452
461
|
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
data/lib/redis.rb
CHANGED
@@ -4,13 +4,26 @@ require "monitor"
|
|
4
4
|
require_relative "redis/errors"
|
5
5
|
|
6
6
|
class Redis
|
7
|
+
class << self
|
8
|
+
attr_reader :exists_returns_integer
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
+
def exists_returns_integer=(value)
|
11
|
+
unless value
|
12
|
+
message = "`Redis#exists(key)` will return an Integer by default in redis-rb 4.3. The option to explicitly " \
|
13
|
+
"disable this behaviour via `Redis.exists_returns_integer` will be removed in 5.0. You should use " \
|
14
|
+
"`exists?` instead."
|
15
|
+
|
16
|
+
::Kernel.warn(message)
|
17
|
+
end
|
18
|
+
|
19
|
+
@exists_returns_integer = value
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_writer :current
|
10
23
|
end
|
11
24
|
|
12
|
-
def self.current
|
13
|
-
@current
|
25
|
+
def self.current
|
26
|
+
@current ||= Redis.new
|
14
27
|
end
|
15
28
|
|
16
29
|
include MonitorMixin
|
@@ -18,18 +31,22 @@ class Redis
|
|
18
31
|
# Create a new client instance
|
19
32
|
#
|
20
33
|
# @param [Hash] options
|
21
|
-
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
34
|
+
# @option options [String] :url (value of the environment variable REDIS_URL) a Redis URL, for a TCP connection:
|
35
|
+
# `redis://:[password]@[hostname]:[port]/[db]` (password, port and database are optional), for a unix socket
|
36
|
+
# connection: `unix://[path to Redis socket]`. This overrides all other options.
|
22
37
|
# @option options [String] :host ("127.0.0.1") server hostname
|
23
|
-
# @option options [
|
38
|
+
# @option options [Integer] :port (6379) server port
|
24
39
|
# @option options [String] :path path to server socket (overrides host and port)
|
25
40
|
# @option options [Float] :timeout (5.0) timeout in seconds
|
26
41
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
27
42
|
# @option options [String] :password Password to authenticate against server
|
28
|
-
# @option options [
|
43
|
+
# @option options [Integer] :db (0) Database to select after initial connect
|
29
44
|
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
30
|
-
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
31
|
-
#
|
32
|
-
# @option options [
|
45
|
+
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
46
|
+
# `CLIENT SETNAME`
|
47
|
+
# @option options [Hash, Integer] :tcp_keepalive Keepalive values, if Integer `intvl` and `probe` are calculated
|
48
|
+
# based on the value, if Hash `time`, `intvl` and `probes` can be specified as a Integer
|
49
|
+
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
33
50
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
34
51
|
# @option options [Array] :sentinels List of sentinels to contact
|
35
52
|
# @option options [Symbol] :role (:master) Role to fetch via Sentinel, either `:master` or `:slave`
|
@@ -53,7 +70,7 @@ class Redis
|
|
53
70
|
end
|
54
71
|
|
55
72
|
# Run code with the client reconnecting
|
56
|
-
def with_reconnect(val=true, &blk)
|
73
|
+
def with_reconnect(val = true, &blk)
|
57
74
|
synchronize do |client|
|
58
75
|
client.with_reconnect(val, &blk)
|
59
76
|
end
|
@@ -96,7 +113,9 @@ class Redis
|
|
96
113
|
# See http://redis.io/topics/pipelining for more details.
|
97
114
|
#
|
98
115
|
def queue(*command)
|
99
|
-
|
116
|
+
synchronize do
|
117
|
+
@queue[Thread.current.object_id] << command
|
118
|
+
end
|
100
119
|
end
|
101
120
|
|
102
121
|
# Sends all commands in the queue.
|
@@ -135,7 +154,7 @@ class Redis
|
|
135
154
|
|
136
155
|
# Change the selected database for the current connection.
|
137
156
|
#
|
138
|
-
# @param [
|
157
|
+
# @param [Integer] db zero-based index of the DB to use (0 to 15)
|
139
158
|
# @return [String] `OK`
|
140
159
|
def select(db)
|
141
160
|
synchronize do |client|
|
@@ -204,7 +223,7 @@ class Redis
|
|
204
223
|
def config(action, *args)
|
205
224
|
synchronize do |client|
|
206
225
|
client.call([:config, action] + args) do |reply|
|
207
|
-
if reply.
|
226
|
+
if reply.is_a?(Array) && action == :get
|
208
227
|
Hashify.call(reply)
|
209
228
|
else
|
210
229
|
reply
|
@@ -234,7 +253,7 @@ class Redis
|
|
234
253
|
|
235
254
|
# Return the number of keys in the selected database.
|
236
255
|
#
|
237
|
-
# @return [
|
256
|
+
# @return [Integer]
|
238
257
|
def dbsize
|
239
258
|
synchronize do |client|
|
240
259
|
client.call([:dbsize])
|
@@ -255,7 +274,7 @@ class Redis
|
|
255
274
|
def flushall(options = nil)
|
256
275
|
synchronize do |client|
|
257
276
|
if options && options[:async]
|
258
|
-
client.call([
|
277
|
+
client.call(%i[flushall async])
|
259
278
|
else
|
260
279
|
client.call([:flushall])
|
261
280
|
end
|
@@ -270,7 +289,7 @@ class Redis
|
|
270
289
|
def flushdb(options = nil)
|
271
290
|
synchronize do |client|
|
272
291
|
if options && options[:async]
|
273
|
-
client.call([
|
292
|
+
client.call(%i[flushdb async])
|
274
293
|
else
|
275
294
|
client.call([:flushdb])
|
276
295
|
end
|
@@ -284,7 +303,7 @@ class Redis
|
|
284
303
|
def info(cmd = nil)
|
285
304
|
synchronize do |client|
|
286
305
|
client.call([:info, cmd].compact) do |reply|
|
287
|
-
if reply.
|
306
|
+
if reply.is_a?(String)
|
288
307
|
reply = HashifyInfo.call(reply)
|
289
308
|
|
290
309
|
if cmd && cmd.to_s == "commandstats"
|
@@ -303,7 +322,7 @@ class Redis
|
|
303
322
|
|
304
323
|
# Get the UNIX time stamp of the last successful save to disk.
|
305
324
|
#
|
306
|
-
# @return [
|
325
|
+
# @return [Integer]
|
307
326
|
def lastsave
|
308
327
|
synchronize do |client|
|
309
328
|
client.call([:lastsave])
|
@@ -355,9 +374,9 @@ class Redis
|
|
355
374
|
# Interact with the slowlog (get, len, reset)
|
356
375
|
#
|
357
376
|
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
358
|
-
# @param [
|
359
|
-
# @return [Array<String>,
|
360
|
-
def slowlog(subcommand, length=nil)
|
377
|
+
# @param [Integer] length maximum number of entries to return
|
378
|
+
# @return [Array<String>, Integer, String] depends on subcommand
|
379
|
+
def slowlog(subcommand, length = nil)
|
361
380
|
synchronize do |client|
|
362
381
|
args = [:slowlog, subcommand]
|
363
382
|
args << length if length
|
@@ -377,12 +396,12 @@ class Redis
|
|
377
396
|
# @example
|
378
397
|
# r.time # => [ 1333093196, 606806 ]
|
379
398
|
#
|
380
|
-
# @return [Array<
|
399
|
+
# @return [Array<Integer>] tuple of seconds since UNIX epoch and
|
381
400
|
# microseconds in the current second
|
382
401
|
def time
|
383
402
|
synchronize do |client|
|
384
403
|
client.call([:time]) do |reply|
|
385
|
-
reply
|
404
|
+
reply&.map(&:to_i)
|
386
405
|
end
|
387
406
|
end
|
388
407
|
end
|
@@ -400,7 +419,7 @@ class Redis
|
|
400
419
|
# Set a key's time to live in seconds.
|
401
420
|
#
|
402
421
|
# @param [String] key
|
403
|
-
# @param [
|
422
|
+
# @param [Integer] seconds time to live
|
404
423
|
# @return [Boolean] whether the timeout was set or not
|
405
424
|
def expire(key, seconds)
|
406
425
|
synchronize do |client|
|
@@ -411,7 +430,7 @@ class Redis
|
|
411
430
|
# Set the expiration for a key as a UNIX timestamp.
|
412
431
|
#
|
413
432
|
# @param [String] key
|
414
|
-
# @param [
|
433
|
+
# @param [Integer] unix_time expiry time specified as a UNIX timestamp
|
415
434
|
# @return [Boolean] whether the timeout was set or not
|
416
435
|
def expireat(key, unix_time)
|
417
436
|
synchronize do |client|
|
@@ -422,7 +441,7 @@ class Redis
|
|
422
441
|
# Get the time to live (in seconds) for a key.
|
423
442
|
#
|
424
443
|
# @param [String] key
|
425
|
-
# @return [
|
444
|
+
# @return [Integer] remaining time to live in seconds.
|
426
445
|
#
|
427
446
|
# In Redis 2.6 or older the command returns -1 if the key does not exist or if
|
428
447
|
# the key exist but has no associated expire.
|
@@ -440,7 +459,7 @@ class Redis
|
|
440
459
|
# Set a key's time to live in milliseconds.
|
441
460
|
#
|
442
461
|
# @param [String] key
|
443
|
-
# @param [
|
462
|
+
# @param [Integer] milliseconds time to live
|
444
463
|
# @return [Boolean] whether the timeout was set or not
|
445
464
|
def pexpire(key, milliseconds)
|
446
465
|
synchronize do |client|
|
@@ -451,7 +470,7 @@ class Redis
|
|
451
470
|
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
|
452
471
|
#
|
453
472
|
# @param [String] key
|
454
|
-
# @param [
|
473
|
+
# @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
|
455
474
|
# @return [Boolean] whether the timeout was set or not
|
456
475
|
def pexpireat(key, ms_unix_time)
|
457
476
|
synchronize do |client|
|
@@ -462,7 +481,7 @@ class Redis
|
|
462
481
|
# Get the time to live (in milliseconds) for a key.
|
463
482
|
#
|
464
483
|
# @param [String] key
|
465
|
-
# @return [
|
484
|
+
# @return [Integer] remaining time to live in milliseconds
|
466
485
|
# In Redis 2.6 or older the command returns -1 if the key does not exist or if
|
467
486
|
# the key exist but has no associated expire.
|
468
487
|
#
|
@@ -495,9 +514,9 @@ class Redis
|
|
495
514
|
# - `:replace => Boolean`: if false, raises an error if key already exists
|
496
515
|
# @raise [Redis::CommandError]
|
497
516
|
# @return [String] `"OK"`
|
498
|
-
def restore(key, ttl, serialized_value,
|
517
|
+
def restore(key, ttl, serialized_value, replace: nil)
|
499
518
|
args = [:restore, key, ttl, serialized_value]
|
500
|
-
args << 'REPLACE' if
|
519
|
+
args << 'REPLACE' if replace
|
501
520
|
|
502
521
|
synchronize do |client|
|
503
522
|
client.call(args)
|
@@ -532,7 +551,7 @@ class Redis
|
|
532
551
|
# Delete one or more keys.
|
533
552
|
#
|
534
553
|
# @param [String, Array<String>] keys
|
535
|
-
# @return [
|
554
|
+
# @return [Integer] number of keys that were deleted
|
536
555
|
def del(*keys)
|
537
556
|
synchronize do |client|
|
538
557
|
client.call([:del] + keys)
|
@@ -542,20 +561,50 @@ class Redis
|
|
542
561
|
# Unlink one or more keys.
|
543
562
|
#
|
544
563
|
# @param [String, Array<String>] keys
|
545
|
-
# @return [
|
564
|
+
# @return [Integer] number of keys that were unlinked
|
546
565
|
def unlink(*keys)
|
547
566
|
synchronize do |client|
|
548
567
|
client.call([:unlink] + keys)
|
549
568
|
end
|
550
569
|
end
|
551
570
|
|
552
|
-
# Determine
|
571
|
+
# Determine how many of the keys exists.
|
553
572
|
#
|
554
|
-
# @param [String]
|
573
|
+
# @param [String, Array<String>] keys
|
574
|
+
# @return [Integer]
|
575
|
+
def exists(*keys)
|
576
|
+
if !Redis.exists_returns_integer && keys.size == 1
|
577
|
+
if Redis.exists_returns_integer.nil?
|
578
|
+
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
|
579
|
+
"should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
|
580
|
+
"true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
|
581
|
+
"`Redis.exists_returns_integer = false`, but this option will be removed in 5.0. " \
|
582
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
583
|
+
|
584
|
+
::Kernel.warn(message)
|
585
|
+
end
|
586
|
+
|
587
|
+
exists?(*keys)
|
588
|
+
else
|
589
|
+
_exists(*keys)
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
def _exists(*keys)
|
594
|
+
synchronize do |client|
|
595
|
+
client.call([:exists, *keys])
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
# Determine if any of the keys exists.
|
600
|
+
#
|
601
|
+
# @param [String, Array<String>] keys
|
555
602
|
# @return [Boolean]
|
556
|
-
def exists(
|
603
|
+
def exists?(*keys)
|
557
604
|
synchronize do |client|
|
558
|
-
client.call([:exists,
|
605
|
+
client.call([:exists, *keys]) do |value|
|
606
|
+
value > 0
|
607
|
+
end
|
559
608
|
end
|
560
609
|
end
|
561
610
|
|
@@ -566,7 +615,7 @@ class Redis
|
|
566
615
|
def keys(pattern = "*")
|
567
616
|
synchronize do |client|
|
568
617
|
client.call([:keys, pattern]) do |reply|
|
569
|
-
if reply.
|
618
|
+
if reply.is_a?(String)
|
570
619
|
reply.split(" ")
|
571
620
|
else
|
572
621
|
reply
|
@@ -592,7 +641,7 @@ class Redis
|
|
592
641
|
# # => "bar"
|
593
642
|
#
|
594
643
|
# @param [String] key
|
595
|
-
# @param [
|
644
|
+
# @param [Integer] db
|
596
645
|
# @return [Boolean] whether the key was moved or not
|
597
646
|
def move(key, db)
|
598
647
|
synchronize do |client|
|
@@ -656,36 +705,33 @@ class Redis
|
|
656
705
|
# - `:order => String`: combination of `ASC`, `DESC` and optionally `ALPHA`
|
657
706
|
# - `:store => String`: key to store the result at
|
658
707
|
#
|
659
|
-
# @return [Array<String>, Array<Array<String>>,
|
708
|
+
# @return [Array<String>, Array<Array<String>>, Integer]
|
660
709
|
# - when `:get` is not specified, or holds a single element, an array of elements
|
661
710
|
# - when `:get` is specified, and holds more than one element, an array of
|
662
711
|
# elements where every element is an array with the result for every
|
663
712
|
# element specified in `:get`
|
664
713
|
# - when `:store` is specified, the number of elements in the stored result
|
665
|
-
def sort(key,
|
666
|
-
args = []
|
667
|
-
|
668
|
-
by = options[:by]
|
669
|
-
args.concat(["BY", by]) if by
|
714
|
+
def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
|
715
|
+
args = [:sort, key]
|
716
|
+
args << "BY" << by if by
|
670
717
|
|
671
|
-
|
672
|
-
|
718
|
+
if limit
|
719
|
+
args << "LIMIT"
|
720
|
+
args.concat(limit)
|
721
|
+
end
|
673
722
|
|
674
|
-
get = Array(
|
675
|
-
|
723
|
+
get = Array(get)
|
724
|
+
get.each do |item|
|
725
|
+
args << "GET" << item
|
726
|
+
end
|
676
727
|
|
677
|
-
order = options[:order]
|
678
728
|
args.concat(order.split(" ")) if order
|
679
|
-
|
680
|
-
store = options[:store]
|
681
|
-
args.concat(["STORE", store]) if store
|
729
|
+
args << "STORE" << store if store
|
682
730
|
|
683
731
|
synchronize do |client|
|
684
|
-
client.call(
|
732
|
+
client.call(args) do |reply|
|
685
733
|
if get.size > 1 && !store
|
686
|
-
if reply
|
687
|
-
reply.each_slice(get.size).to_a
|
688
|
-
end
|
734
|
+
reply.each_slice(get.size).to_a if reply
|
689
735
|
else
|
690
736
|
reply
|
691
737
|
end
|
@@ -710,7 +756,7 @@ class Redis
|
|
710
756
|
# # => 4
|
711
757
|
#
|
712
758
|
# @param [String] key
|
713
|
-
# @return [
|
759
|
+
# @return [Integer] value after decrementing it
|
714
760
|
def decr(key)
|
715
761
|
synchronize do |client|
|
716
762
|
client.call([:decr, key])
|
@@ -724,8 +770,8 @@ class Redis
|
|
724
770
|
# # => 0
|
725
771
|
#
|
726
772
|
# @param [String] key
|
727
|
-
# @param [
|
728
|
-
# @return [
|
773
|
+
# @param [Integer] decrement
|
774
|
+
# @return [Integer] value after decrementing it
|
729
775
|
def decrby(key, decrement)
|
730
776
|
synchronize do |client|
|
731
777
|
client.call([:decrby, key, decrement])
|
@@ -739,7 +785,7 @@ class Redis
|
|
739
785
|
# # => 6
|
740
786
|
#
|
741
787
|
# @param [String] key
|
742
|
-
# @return [
|
788
|
+
# @return [Integer] value after incrementing it
|
743
789
|
def incr(key)
|
744
790
|
synchronize do |client|
|
745
791
|
client.call([:incr, key])
|
@@ -753,8 +799,8 @@ class Redis
|
|
753
799
|
# # => 10
|
754
800
|
#
|
755
801
|
# @param [String] key
|
756
|
-
# @param [
|
757
|
-
# @return [
|
802
|
+
# @param [Integer] increment
|
803
|
+
# @return [Integer] value after incrementing it
|
758
804
|
def incrby(key, increment)
|
759
805
|
synchronize do |client|
|
760
806
|
client.call([:incrby, key, increment])
|
@@ -781,31 +827,25 @@ class Redis
|
|
781
827
|
# @param [String] key
|
782
828
|
# @param [String] value
|
783
829
|
# @param [Hash] options
|
784
|
-
# - `:ex =>
|
785
|
-
# - `:px =>
|
830
|
+
# - `:ex => Integer`: Set the specified expire time, in seconds.
|
831
|
+
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
786
832
|
# - `:nx => true`: Only set the key if it does not already exist.
|
787
833
|
# - `:xx => true`: Only set the key if it already exist.
|
834
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
788
835
|
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
789
|
-
def set(key, value,
|
790
|
-
args = []
|
791
|
-
|
792
|
-
|
793
|
-
args
|
794
|
-
|
795
|
-
|
796
|
-
args.concat(["PX", px]) if px
|
797
|
-
|
798
|
-
nx = options[:nx]
|
799
|
-
args.concat(["NX"]) if nx
|
800
|
-
|
801
|
-
xx = options[:xx]
|
802
|
-
args.concat(["XX"]) if xx
|
836
|
+
def set(key, value, ex: nil, px: nil, nx: nil, xx: nil, keepttl: nil)
|
837
|
+
args = [:set, key, value.to_s]
|
838
|
+
args << "EX" << ex if ex
|
839
|
+
args << "PX" << px if px
|
840
|
+
args << "NX" if nx
|
841
|
+
args << "XX" if xx
|
842
|
+
args << "KEEPTTL" if keepttl
|
803
843
|
|
804
844
|
synchronize do |client|
|
805
845
|
if nx || xx
|
806
|
-
client.call(
|
846
|
+
client.call(args, &BoolifySet)
|
807
847
|
else
|
808
|
-
client.call(
|
848
|
+
client.call(args)
|
809
849
|
end
|
810
850
|
end
|
811
851
|
end
|
@@ -813,7 +853,7 @@ class Redis
|
|
813
853
|
# Set the time to live in seconds of a key.
|
814
854
|
#
|
815
855
|
# @param [String] key
|
816
|
-
# @param [
|
856
|
+
# @param [Integer] ttl
|
817
857
|
# @param [String] value
|
818
858
|
# @return [String] `"OK"`
|
819
859
|
def setex(key, ttl, value)
|
@@ -825,7 +865,7 @@ class Redis
|
|
825
865
|
# Set the time to live in milliseconds of a key.
|
826
866
|
#
|
827
867
|
# @param [String] key
|
828
|
-
# @param [
|
868
|
+
# @param [Integer] ttl
|
829
869
|
# @param [String] value
|
830
870
|
# @return [String] `"OK"`
|
831
871
|
def psetex(key, ttl, value)
|
@@ -887,7 +927,7 @@ class Redis
|
|
887
927
|
# @see #mapped_msetnx
|
888
928
|
def msetnx(*args)
|
889
929
|
synchronize do |client|
|
890
|
-
client.call([:msetnx
|
930
|
+
client.call([:msetnx, *args], &Boolify)
|
891
931
|
end
|
892
932
|
end
|
893
933
|
|
@@ -918,7 +958,7 @@ class Redis
|
|
918
958
|
# Get the values of all the given keys.
|
919
959
|
#
|
920
960
|
# @example
|
921
|
-
# redis.mget("key1", "
|
961
|
+
# redis.mget("key1", "key2")
|
922
962
|
# # => ["v1", "v2"]
|
923
963
|
#
|
924
964
|
# @param [Array<String>] keys
|
@@ -927,7 +967,7 @@ class Redis
|
|
927
967
|
# @see #mapped_mget
|
928
968
|
def mget(*keys, &blk)
|
929
969
|
synchronize do |client|
|
930
|
-
client.call([:mget
|
970
|
+
client.call([:mget, *keys], &blk)
|
931
971
|
end
|
932
972
|
end
|
933
973
|
|
@@ -943,7 +983,7 @@ class Redis
|
|
943
983
|
# @see #mget
|
944
984
|
def mapped_mget(*keys)
|
945
985
|
mget(*keys) do |reply|
|
946
|
-
if reply.
|
986
|
+
if reply.is_a?(Array)
|
947
987
|
Hash[keys.zip(reply)]
|
948
988
|
else
|
949
989
|
reply
|
@@ -954,9 +994,9 @@ class Redis
|
|
954
994
|
# Overwrite part of a string at key starting at the specified offset.
|
955
995
|
#
|
956
996
|
# @param [String] key
|
957
|
-
# @param [
|
997
|
+
# @param [Integer] offset byte offset
|
958
998
|
# @param [String] value
|
959
|
-
# @return [
|
999
|
+
# @return [Integer] length of the string after it was modified
|
960
1000
|
def setrange(key, offset, value)
|
961
1001
|
synchronize do |client|
|
962
1002
|
client.call([:setrange, key, offset, value.to_s])
|
@@ -966,10 +1006,10 @@ class Redis
|
|
966
1006
|
# Get a substring of the string stored at a key.
|
967
1007
|
#
|
968
1008
|
# @param [String] key
|
969
|
-
# @param [
|
970
|
-
# @param [
|
1009
|
+
# @param [Integer] start zero-based start offset
|
1010
|
+
# @param [Integer] stop zero-based end offset. Use -1 for representing
|
971
1011
|
# the end of the string
|
972
|
-
# @return [
|
1012
|
+
# @return [Integer] `0` or `1`
|
973
1013
|
def getrange(key, start, stop)
|
974
1014
|
synchronize do |client|
|
975
1015
|
client.call([:getrange, key, start, stop])
|
@@ -979,9 +1019,9 @@ class Redis
|
|
979
1019
|
# Sets or clears the bit at offset in the string value stored at key.
|
980
1020
|
#
|
981
1021
|
# @param [String] key
|
982
|
-
# @param [
|
983
|
-
# @param [
|
984
|
-
# @return [
|
1022
|
+
# @param [Integer] offset bit offset
|
1023
|
+
# @param [Integer] value bit value `0` or `1`
|
1024
|
+
# @return [Integer] the original bit value stored at `offset`
|
985
1025
|
def setbit(key, offset, value)
|
986
1026
|
synchronize do |client|
|
987
1027
|
client.call([:setbit, key, offset, value])
|
@@ -991,8 +1031,8 @@ class Redis
|
|
991
1031
|
# Returns the bit value at offset in the string value stored at key.
|
992
1032
|
#
|
993
1033
|
# @param [String] key
|
994
|
-
# @param [
|
995
|
-
# @return [
|
1034
|
+
# @param [Integer] offset bit offset
|
1035
|
+
# @return [Integer] `0` or `1`
|
996
1036
|
def getbit(key, offset)
|
997
1037
|
synchronize do |client|
|
998
1038
|
client.call([:getbit, key, offset])
|
@@ -1003,7 +1043,7 @@ class Redis
|
|
1003
1043
|
#
|
1004
1044
|
# @param [String] key
|
1005
1045
|
# @param [String] value value to append
|
1006
|
-
# @return [
|
1046
|
+
# @return [Integer] length of the string after appending
|
1007
1047
|
def append(key, value)
|
1008
1048
|
synchronize do |client|
|
1009
1049
|
client.call([:append, key, value])
|
@@ -1013,9 +1053,9 @@ class Redis
|
|
1013
1053
|
# Count the number of set bits in a range of the string value stored at key.
|
1014
1054
|
#
|
1015
1055
|
# @param [String] key
|
1016
|
-
# @param [
|
1017
|
-
# @param [
|
1018
|
-
# @return [
|
1056
|
+
# @param [Integer] start start index
|
1057
|
+
# @param [Integer] stop stop index
|
1058
|
+
# @return [Integer] the number of bits set to 1
|
1019
1059
|
def bitcount(key, start = 0, stop = -1)
|
1020
1060
|
synchronize do |client|
|
1021
1061
|
client.call([:bitcount, key, start, stop])
|
@@ -1027,25 +1067,23 @@ class Redis
|
|
1027
1067
|
# @param [String] operation e.g. `and`, `or`, `xor`, `not`
|
1028
1068
|
# @param [String] destkey destination key
|
1029
1069
|
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
1030
|
-
# @return [
|
1070
|
+
# @return [Integer] the length of the string stored in `destkey`
|
1031
1071
|
def bitop(operation, destkey, *keys)
|
1032
1072
|
synchronize do |client|
|
1033
|
-
client.call([:bitop, operation, destkey
|
1073
|
+
client.call([:bitop, operation, destkey, *keys])
|
1034
1074
|
end
|
1035
1075
|
end
|
1036
1076
|
|
1037
1077
|
# Return the position of the first bit set to 1 or 0 in a string.
|
1038
1078
|
#
|
1039
1079
|
# @param [String] key
|
1040
|
-
# @param [
|
1041
|
-
# @param [
|
1042
|
-
# @param [
|
1043
|
-
# @return [
|
1080
|
+
# @param [Integer] bit whether to look for the first 1 or 0 bit
|
1081
|
+
# @param [Integer] start start index
|
1082
|
+
# @param [Integer] stop stop index
|
1083
|
+
# @return [Integer] the position of the first 1/0 bit.
|
1044
1084
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
1045
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
1046
|
-
|
1047
|
-
raise(ArgumentError, 'stop parameter specified without start parameter')
|
1048
|
-
end
|
1085
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
1086
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
1049
1087
|
|
1050
1088
|
synchronize do |client|
|
1051
1089
|
command = [:bitpos, key, bit]
|
@@ -1070,7 +1108,7 @@ class Redis
|
|
1070
1108
|
# Get the length of the value stored in a key.
|
1071
1109
|
#
|
1072
1110
|
# @param [String] key
|
1073
|
-
# @return [
|
1111
|
+
# @return [Integer] the length of the value stored in the key, or 0
|
1074
1112
|
# if the key does not exist
|
1075
1113
|
def strlen(key)
|
1076
1114
|
synchronize do |client|
|
@@ -1081,7 +1119,7 @@ class Redis
|
|
1081
1119
|
# Get the length of a list.
|
1082
1120
|
#
|
1083
1121
|
# @param [String] key
|
1084
|
-
# @return [
|
1122
|
+
# @return [Integer]
|
1085
1123
|
def llen(key)
|
1086
1124
|
synchronize do |client|
|
1087
1125
|
client.call([:llen, key])
|
@@ -1092,7 +1130,7 @@ class Redis
|
|
1092
1130
|
#
|
1093
1131
|
# @param [String] key
|
1094
1132
|
# @param [String, Array<String>] value string value, or array of string values to push
|
1095
|
-
# @return [
|
1133
|
+
# @return [Integer] the length of the list after the push operation
|
1096
1134
|
def lpush(key, value)
|
1097
1135
|
synchronize do |client|
|
1098
1136
|
client.call([:lpush, key, value])
|
@@ -1103,7 +1141,7 @@ class Redis
|
|
1103
1141
|
#
|
1104
1142
|
# @param [String] key
|
1105
1143
|
# @param [String] value
|
1106
|
-
# @return [
|
1144
|
+
# @return [Integer] the length of the list after the push operation
|
1107
1145
|
def lpushx(key, value)
|
1108
1146
|
synchronize do |client|
|
1109
1147
|
client.call([:lpushx, key, value])
|
@@ -1114,7 +1152,7 @@ class Redis
|
|
1114
1152
|
#
|
1115
1153
|
# @param [String] key
|
1116
1154
|
# @param [String, Array<String>] value string value, or array of string values to push
|
1117
|
-
# @return [
|
1155
|
+
# @return [Integer] the length of the list after the push operation
|
1118
1156
|
def rpush(key, value)
|
1119
1157
|
synchronize do |client|
|
1120
1158
|
client.call([:rpush, key, value])
|
@@ -1125,7 +1163,7 @@ class Redis
|
|
1125
1163
|
#
|
1126
1164
|
# @param [String] key
|
1127
1165
|
# @param [String] value
|
1128
|
-
# @return [
|
1166
|
+
# @return [Integer] the length of the list after the push operation
|
1129
1167
|
def rpushx(key, value)
|
1130
1168
|
synchronize do |client|
|
1131
1169
|
client.call([:rpushx, key, value])
|
@@ -1164,21 +1202,21 @@ class Redis
|
|
1164
1202
|
end
|
1165
1203
|
|
1166
1204
|
def _bpop(cmd, args, &blk)
|
1167
|
-
|
1168
|
-
|
1169
|
-
if args.last.is_a?(Hash)
|
1205
|
+
timeout = if args.last.is_a?(Hash)
|
1170
1206
|
options = args.pop
|
1207
|
+
options[:timeout]
|
1171
1208
|
elsif args.last.respond_to?(:to_int)
|
1172
1209
|
# Issue deprecation notice in obnoxious mode...
|
1173
|
-
|
1210
|
+
args.pop.to_int
|
1174
1211
|
end
|
1175
1212
|
|
1213
|
+
timeout ||= 0
|
1214
|
+
|
1176
1215
|
if args.size > 1
|
1177
1216
|
# Issue deprecation notice in obnoxious mode...
|
1178
1217
|
end
|
1179
1218
|
|
1180
1219
|
keys = args.flatten
|
1181
|
-
timeout = options[:timeout] || 0
|
1182
1220
|
|
1183
1221
|
synchronize do |client|
|
1184
1222
|
command = [cmd, keys, timeout]
|
@@ -1203,7 +1241,7 @@ class Redis
|
|
1203
1241
|
# @param [String, Array<String>] keys one or more keys to perform the
|
1204
1242
|
# blocking pop on
|
1205
1243
|
# @param [Hash] options
|
1206
|
-
# - `:timeout =>
|
1244
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1207
1245
|
#
|
1208
1246
|
# @return [nil, [String, String]]
|
1209
1247
|
# - `nil` when the operation timed out
|
@@ -1217,7 +1255,7 @@ class Redis
|
|
1217
1255
|
# @param [String, Array<String>] keys one or more keys to perform the
|
1218
1256
|
# blocking pop on
|
1219
1257
|
# @param [Hash] options
|
1220
|
-
# - `:timeout =>
|
1258
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1221
1259
|
#
|
1222
1260
|
# @return [nil, [String, String]]
|
1223
1261
|
# - `nil` when the operation timed out
|
@@ -1234,20 +1272,12 @@ class Redis
|
|
1234
1272
|
# @param [String] source source key
|
1235
1273
|
# @param [String] destination destination key
|
1236
1274
|
# @param [Hash] options
|
1237
|
-
# - `:timeout =>
|
1275
|
+
# - `:timeout => Integer`: timeout in seconds, defaults to no timeout
|
1238
1276
|
#
|
1239
1277
|
# @return [nil, String]
|
1240
1278
|
# - `nil` when the operation timed out
|
1241
1279
|
# - the element was popped and pushed otherwise
|
1242
|
-
def brpoplpush(source, destination,
|
1243
|
-
case options
|
1244
|
-
when Integer
|
1245
|
-
# Issue deprecation notice in obnoxious mode...
|
1246
|
-
options = { :timeout => options }
|
1247
|
-
end
|
1248
|
-
|
1249
|
-
timeout = options[:timeout] || 0
|
1250
|
-
|
1280
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
|
1251
1281
|
synchronize do |client|
|
1252
1282
|
command = [:brpoplpush, source, destination, timeout]
|
1253
1283
|
timeout += client.timeout if timeout > 0
|
@@ -1258,7 +1288,7 @@ class Redis
|
|
1258
1288
|
# Get an element from a list by its index.
|
1259
1289
|
#
|
1260
1290
|
# @param [String] key
|
1261
|
-
# @param [
|
1291
|
+
# @param [Integer] index
|
1262
1292
|
# @return [String]
|
1263
1293
|
def lindex(key, index)
|
1264
1294
|
synchronize do |client|
|
@@ -1272,7 +1302,7 @@ class Redis
|
|
1272
1302
|
# @param [String, Symbol] where `BEFORE` or `AFTER`
|
1273
1303
|
# @param [String] pivot reference element
|
1274
1304
|
# @param [String] value
|
1275
|
-
# @return [
|
1305
|
+
# @return [Integer] length of the list after the insert operation, or `-1`
|
1276
1306
|
# when the element `pivot` was not found
|
1277
1307
|
def linsert(key, where, pivot, value)
|
1278
1308
|
synchronize do |client|
|
@@ -1283,8 +1313,8 @@ class Redis
|
|
1283
1313
|
# Get a range of elements from a list.
|
1284
1314
|
#
|
1285
1315
|
# @param [String] key
|
1286
|
-
# @param [
|
1287
|
-
# @param [
|
1316
|
+
# @param [Integer] start start index
|
1317
|
+
# @param [Integer] stop stop index
|
1288
1318
|
# @return [Array<String>]
|
1289
1319
|
def lrange(key, start, stop)
|
1290
1320
|
synchronize do |client|
|
@@ -1295,12 +1325,12 @@ class Redis
|
|
1295
1325
|
# Remove elements from a list.
|
1296
1326
|
#
|
1297
1327
|
# @param [String] key
|
1298
|
-
# @param [
|
1328
|
+
# @param [Integer] count number of elements to remove. Use a positive
|
1299
1329
|
# value to remove the first `count` occurrences of `value`. A negative
|
1300
1330
|
# value to remove the last `count` occurrences of `value`. Or zero, to
|
1301
1331
|
# remove all occurrences of `value` from the list.
|
1302
1332
|
# @param [String] value
|
1303
|
-
# @return [
|
1333
|
+
# @return [Integer] the number of removed elements
|
1304
1334
|
def lrem(key, count, value)
|
1305
1335
|
synchronize do |client|
|
1306
1336
|
client.call([:lrem, key, count, value])
|
@@ -1310,7 +1340,7 @@ class Redis
|
|
1310
1340
|
# Set the value of an element in a list by its index.
|
1311
1341
|
#
|
1312
1342
|
# @param [String] key
|
1313
|
-
# @param [
|
1343
|
+
# @param [Integer] index
|
1314
1344
|
# @param [String] value
|
1315
1345
|
# @return [String] `OK`
|
1316
1346
|
def lset(key, index, value)
|
@@ -1322,8 +1352,8 @@ class Redis
|
|
1322
1352
|
# Trim a list to the specified range.
|
1323
1353
|
#
|
1324
1354
|
# @param [String] key
|
1325
|
-
# @param [
|
1326
|
-
# @param [
|
1355
|
+
# @param [Integer] start start index
|
1356
|
+
# @param [Integer] stop stop index
|
1327
1357
|
# @return [String] `OK`
|
1328
1358
|
def ltrim(key, start, stop)
|
1329
1359
|
synchronize do |client|
|
@@ -1334,7 +1364,7 @@ class Redis
|
|
1334
1364
|
# Get the number of members in a set.
|
1335
1365
|
#
|
1336
1366
|
# @param [String] key
|
1337
|
-
# @return [
|
1367
|
+
# @return [Integer]
|
1338
1368
|
def scard(key)
|
1339
1369
|
synchronize do |client|
|
1340
1370
|
client.call([:scard, key])
|
@@ -1345,8 +1375,8 @@ class Redis
|
|
1345
1375
|
#
|
1346
1376
|
# @param [String] key
|
1347
1377
|
# @param [String, Array<String>] member one member, or array of members
|
1348
|
-
# @return [Boolean,
|
1349
|
-
# holding whether or not adding the member succeeded, or `
|
1378
|
+
# @return [Boolean, Integer] `Boolean` when a single member is specified,
|
1379
|
+
# holding whether or not adding the member succeeded, or `Integer` when an
|
1350
1380
|
# array of members is specified, holding the number of members that were
|
1351
1381
|
# successfully added
|
1352
1382
|
def sadd(key, member)
|
@@ -1367,8 +1397,8 @@ class Redis
|
|
1367
1397
|
#
|
1368
1398
|
# @param [String] key
|
1369
1399
|
# @param [String, Array<String>] member one member, or array of members
|
1370
|
-
# @return [Boolean,
|
1371
|
-
# holding whether or not removing the member succeeded, or `
|
1400
|
+
# @return [Boolean, Integer] `Boolean` when a single member is specified,
|
1401
|
+
# holding whether or not removing the member succeeded, or `Integer` when an
|
1372
1402
|
# array of members is specified, holding the number of members that were
|
1373
1403
|
# successfully removed
|
1374
1404
|
def srem(key, member)
|
@@ -1389,7 +1419,7 @@ class Redis
|
|
1389
1419
|
#
|
1390
1420
|
# @param [String] key
|
1391
1421
|
# @return [String]
|
1392
|
-
# @param [
|
1422
|
+
# @param [Integer] count
|
1393
1423
|
def spop(key, count = nil)
|
1394
1424
|
synchronize do |client|
|
1395
1425
|
if count.nil?
|
@@ -1403,7 +1433,7 @@ class Redis
|
|
1403
1433
|
# Get one or more random members from a set.
|
1404
1434
|
#
|
1405
1435
|
# @param [String] key
|
1406
|
-
# @param [
|
1436
|
+
# @param [Integer] count
|
1407
1437
|
# @return [String]
|
1408
1438
|
def srandmember(key, count = nil)
|
1409
1439
|
synchronize do |client|
|
@@ -1454,7 +1484,7 @@ class Redis
|
|
1454
1484
|
# @return [Array<String>] members in the difference
|
1455
1485
|
def sdiff(*keys)
|
1456
1486
|
synchronize do |client|
|
1457
|
-
client.call([:sdiff
|
1487
|
+
client.call([:sdiff, *keys])
|
1458
1488
|
end
|
1459
1489
|
end
|
1460
1490
|
|
@@ -1462,10 +1492,10 @@ class Redis
|
|
1462
1492
|
#
|
1463
1493
|
# @param [String] destination destination key
|
1464
1494
|
# @param [String, Array<String>] keys keys pointing to sets to subtract
|
1465
|
-
# @return [
|
1495
|
+
# @return [Integer] number of elements in the resulting set
|
1466
1496
|
def sdiffstore(destination, *keys)
|
1467
1497
|
synchronize do |client|
|
1468
|
-
client.call([:sdiffstore, destination
|
1498
|
+
client.call([:sdiffstore, destination, *keys])
|
1469
1499
|
end
|
1470
1500
|
end
|
1471
1501
|
|
@@ -1475,7 +1505,7 @@ class Redis
|
|
1475
1505
|
# @return [Array<String>] members in the intersection
|
1476
1506
|
def sinter(*keys)
|
1477
1507
|
synchronize do |client|
|
1478
|
-
client.call([:sinter
|
1508
|
+
client.call([:sinter, *keys])
|
1479
1509
|
end
|
1480
1510
|
end
|
1481
1511
|
|
@@ -1483,10 +1513,10 @@ class Redis
|
|
1483
1513
|
#
|
1484
1514
|
# @param [String] destination destination key
|
1485
1515
|
# @param [String, Array<String>] keys keys pointing to sets to intersect
|
1486
|
-
# @return [
|
1516
|
+
# @return [Integer] number of elements in the resulting set
|
1487
1517
|
def sinterstore(destination, *keys)
|
1488
1518
|
synchronize do |client|
|
1489
|
-
client.call([:sinterstore, destination
|
1519
|
+
client.call([:sinterstore, destination, *keys])
|
1490
1520
|
end
|
1491
1521
|
end
|
1492
1522
|
|
@@ -1496,7 +1526,7 @@ class Redis
|
|
1496
1526
|
# @return [Array<String>] members in the union
|
1497
1527
|
def sunion(*keys)
|
1498
1528
|
synchronize do |client|
|
1499
|
-
client.call([:sunion
|
1529
|
+
client.call([:sunion, *keys])
|
1500
1530
|
end
|
1501
1531
|
end
|
1502
1532
|
|
@@ -1504,10 +1534,10 @@ class Redis
|
|
1504
1534
|
#
|
1505
1535
|
# @param [String] destination destination key
|
1506
1536
|
# @param [String, Array<String>] keys keys pointing to sets to unify
|
1507
|
-
# @return [
|
1537
|
+
# @return [Integer] number of elements in the resulting set
|
1508
1538
|
def sunionstore(destination, *keys)
|
1509
1539
|
synchronize do |client|
|
1510
|
-
client.call([:sunionstore, destination
|
1540
|
+
client.call([:sunionstore, destination, *keys])
|
1511
1541
|
end
|
1512
1542
|
end
|
1513
1543
|
|
@@ -1518,7 +1548,7 @@ class Redis
|
|
1518
1548
|
# # => 4
|
1519
1549
|
#
|
1520
1550
|
# @param [String] key
|
1521
|
-
# @return [
|
1551
|
+
# @return [Integer]
|
1522
1552
|
def zcard(key)
|
1523
1553
|
synchronize do |client|
|
1524
1554
|
client.call([:zcard, key])
|
@@ -1549,38 +1579,27 @@ class Redis
|
|
1549
1579
|
# - `:incr => true`: When this option is specified ZADD acts like
|
1550
1580
|
# ZINCRBY; only one score-element pair can be specified in this mode
|
1551
1581
|
#
|
1552
|
-
# @return [Boolean,
|
1582
|
+
# @return [Boolean, Integer, Float]
|
1553
1583
|
# - `Boolean` when a single pair is specified, holding whether or not it was
|
1554
1584
|
# **added** to the sorted set.
|
1555
|
-
# - `
|
1585
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
1556
1586
|
# pairs that were **added** to the sorted set.
|
1557
1587
|
# - `Float` when option :incr is specified, holding the score of the member
|
1558
1588
|
# after incrementing it.
|
1559
|
-
def zadd(key, *args
|
1560
|
-
|
1561
|
-
if
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
zadd_options << "NX" if nx
|
1566
|
-
|
1567
|
-
xx = options[:xx]
|
1568
|
-
zadd_options << "XX" if xx
|
1569
|
-
|
1570
|
-
ch = options[:ch]
|
1571
|
-
zadd_options << "CH" if ch
|
1572
|
-
|
1573
|
-
incr = options[:incr]
|
1574
|
-
zadd_options << "INCR" if incr
|
1575
|
-
end
|
1589
|
+
def zadd(key, *args, nx: nil, xx: nil, ch: nil, incr: nil)
|
1590
|
+
command = [:zadd, key]
|
1591
|
+
command << "NX" if nx
|
1592
|
+
command << "XX" if xx
|
1593
|
+
command << "CH" if ch
|
1594
|
+
command << "INCR" if incr
|
1576
1595
|
|
1577
1596
|
synchronize do |client|
|
1578
1597
|
if args.size == 1 && args[0].is_a?(Array)
|
1579
1598
|
# Variadic: return float if INCR, integer if !INCR
|
1580
|
-
client.call(
|
1599
|
+
client.call(command + args[0], &(incr ? Floatify : nil))
|
1581
1600
|
elsif args.size == 2
|
1582
1601
|
# Single pair: return float if INCR, boolean if !INCR
|
1583
|
-
client.call(
|
1602
|
+
client.call(command + args, &(incr ? Floatify : Boolify))
|
1584
1603
|
else
|
1585
1604
|
raise ArgumentError, "wrong number of arguments"
|
1586
1605
|
end
|
@@ -1615,10 +1634,10 @@ class Redis
|
|
1615
1634
|
# - a single member
|
1616
1635
|
# - an array of members
|
1617
1636
|
#
|
1618
|
-
# @return [Boolean,
|
1637
|
+
# @return [Boolean, Integer]
|
1619
1638
|
# - `Boolean` when a single member is specified, holding whether or not it
|
1620
1639
|
# was removed from the sorted set
|
1621
|
-
# - `
|
1640
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
1622
1641
|
# members that were removed to the sorted set
|
1623
1642
|
def zrem(key, member)
|
1624
1643
|
synchronize do |client|
|
@@ -1743,18 +1762,16 @@ class Redis
|
|
1743
1762
|
# # => [["a", 32.0], ["b", 64.0]]
|
1744
1763
|
#
|
1745
1764
|
# @param [String] key
|
1746
|
-
# @param [
|
1747
|
-
# @param [
|
1765
|
+
# @param [Integer] start start index
|
1766
|
+
# @param [Integer] stop stop index
|
1748
1767
|
# @param [Hash] options
|
1749
1768
|
# - `:with_scores => true`: include scores in output
|
1750
1769
|
#
|
1751
1770
|
# @return [Array<String>, Array<[String, Float]>]
|
1752
1771
|
# - when `:with_scores` is not specified, an array of members
|
1753
1772
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1754
|
-
def zrange(key, start, stop,
|
1755
|
-
args = []
|
1756
|
-
|
1757
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1773
|
+
def zrange(key, start, stop, withscores: false, with_scores: withscores)
|
1774
|
+
args = [:zrange, key, start, stop]
|
1758
1775
|
|
1759
1776
|
if with_scores
|
1760
1777
|
args << "WITHSCORES"
|
@@ -1762,7 +1779,7 @@ class Redis
|
|
1762
1779
|
end
|
1763
1780
|
|
1764
1781
|
synchronize do |client|
|
1765
|
-
client.call(
|
1782
|
+
client.call(args, &block)
|
1766
1783
|
end
|
1767
1784
|
end
|
1768
1785
|
|
@@ -1777,10 +1794,8 @@ class Redis
|
|
1777
1794
|
# # => [["b", 64.0], ["a", 32.0]]
|
1778
1795
|
#
|
1779
1796
|
# @see #zrange
|
1780
|
-
def zrevrange(key, start, stop,
|
1781
|
-
args = []
|
1782
|
-
|
1783
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1797
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
1798
|
+
args = [:zrevrange, key, start, stop]
|
1784
1799
|
|
1785
1800
|
if with_scores
|
1786
1801
|
args << "WITHSCORES"
|
@@ -1788,7 +1803,7 @@ class Redis
|
|
1788
1803
|
end
|
1789
1804
|
|
1790
1805
|
synchronize do |client|
|
1791
|
-
client.call(
|
1806
|
+
client.call(args, &block)
|
1792
1807
|
end
|
1793
1808
|
end
|
1794
1809
|
|
@@ -1796,7 +1811,7 @@ class Redis
|
|
1796
1811
|
#
|
1797
1812
|
# @param [String] key
|
1798
1813
|
# @param [String] member
|
1799
|
-
# @return [
|
1814
|
+
# @return [Integer]
|
1800
1815
|
def zrank(key, member)
|
1801
1816
|
synchronize do |client|
|
1802
1817
|
client.call([:zrank, key, member])
|
@@ -1808,7 +1823,7 @@ class Redis
|
|
1808
1823
|
#
|
1809
1824
|
# @param [String] key
|
1810
1825
|
# @param [String] member
|
1811
|
-
# @return [
|
1826
|
+
# @return [Integer]
|
1812
1827
|
def zrevrank(key, member)
|
1813
1828
|
synchronize do |client|
|
1814
1829
|
client.call([:zrevrank, key, member])
|
@@ -1825,9 +1840,9 @@ class Redis
|
|
1825
1840
|
# # => 5
|
1826
1841
|
#
|
1827
1842
|
# @param [String] key
|
1828
|
-
# @param [
|
1829
|
-
# @param [
|
1830
|
-
# @return [
|
1843
|
+
# @param [Integer] start start index
|
1844
|
+
# @param [Integer] stop stop index
|
1845
|
+
# @return [Integer] number of members that were removed
|
1831
1846
|
def zremrangebyrank(key, start, stop)
|
1832
1847
|
synchronize do |client|
|
1833
1848
|
client.call([:zremrangebyrank, key, start, stop])
|
@@ -1851,7 +1866,7 @@ class Redis
|
|
1851
1866
|
# - inclusive maximum is specified by prefixing `(`
|
1852
1867
|
# - exclusive maximum is specified by prefixing `[`
|
1853
1868
|
#
|
1854
|
-
# @return [
|
1869
|
+
# @return [Integer] number of members within the specified lexicographical range
|
1855
1870
|
def zlexcount(key, min, max)
|
1856
1871
|
synchronize do |client|
|
1857
1872
|
client.call([:zlexcount, key, min, max])
|
@@ -1879,14 +1894,16 @@ class Redis
|
|
1879
1894
|
# `count` members
|
1880
1895
|
#
|
1881
1896
|
# @return [Array<String>, Array<[String, Float]>]
|
1882
|
-
def zrangebylex(key, min, max,
|
1883
|
-
args = []
|
1897
|
+
def zrangebylex(key, min, max, limit: nil)
|
1898
|
+
args = [:zrangebylex, key, min, max]
|
1884
1899
|
|
1885
|
-
|
1886
|
-
|
1900
|
+
if limit
|
1901
|
+
args << "LIMIT"
|
1902
|
+
args.concat(limit)
|
1903
|
+
end
|
1887
1904
|
|
1888
1905
|
synchronize do |client|
|
1889
|
-
client.call(
|
1906
|
+
client.call(args)
|
1890
1907
|
end
|
1891
1908
|
end
|
1892
1909
|
|
@@ -1901,14 +1918,16 @@ class Redis
|
|
1901
1918
|
# # => ["abbygail", "abby"]
|
1902
1919
|
#
|
1903
1920
|
# @see #zrangebylex
|
1904
|
-
def zrevrangebylex(key, max, min,
|
1905
|
-
args = []
|
1921
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
1922
|
+
args = [:zrevrangebylex, key, max, min]
|
1906
1923
|
|
1907
|
-
|
1908
|
-
|
1924
|
+
if limit
|
1925
|
+
args << "LIMIT"
|
1926
|
+
args.concat(limit)
|
1927
|
+
end
|
1909
1928
|
|
1910
1929
|
synchronize do |client|
|
1911
|
-
client.call(
|
1930
|
+
client.call(args)
|
1912
1931
|
end
|
1913
1932
|
end
|
1914
1933
|
|
@@ -1939,21 +1958,21 @@ class Redis
|
|
1939
1958
|
# @return [Array<String>, Array<[String, Float]>]
|
1940
1959
|
# - when `:with_scores` is not specified, an array of members
|
1941
1960
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1942
|
-
def zrangebyscore(key, min, max,
|
1943
|
-
args = []
|
1944
|
-
|
1945
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1961
|
+
def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
|
1962
|
+
args = [:zrangebyscore, key, min, max]
|
1946
1963
|
|
1947
1964
|
if with_scores
|
1948
1965
|
args << "WITHSCORES"
|
1949
1966
|
block = FloatifyPairs
|
1950
1967
|
end
|
1951
1968
|
|
1952
|
-
|
1953
|
-
|
1969
|
+
if limit
|
1970
|
+
args << "LIMIT"
|
1971
|
+
args.concat(limit)
|
1972
|
+
end
|
1954
1973
|
|
1955
1974
|
synchronize do |client|
|
1956
|
-
client.call(
|
1975
|
+
client.call(args, &block)
|
1957
1976
|
end
|
1958
1977
|
end
|
1959
1978
|
|
@@ -1971,21 +1990,21 @@ class Redis
|
|
1971
1990
|
# # => [["b", 64.0], ["a", 32.0]]
|
1972
1991
|
#
|
1973
1992
|
# @see #zrangebyscore
|
1974
|
-
def zrevrangebyscore(key, max, min,
|
1975
|
-
args = []
|
1976
|
-
|
1977
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1993
|
+
def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
|
1994
|
+
args = [:zrevrangebyscore, key, max, min]
|
1978
1995
|
|
1979
1996
|
if with_scores
|
1980
|
-
args <<
|
1997
|
+
args << "WITHSCORES"
|
1981
1998
|
block = FloatifyPairs
|
1982
1999
|
end
|
1983
2000
|
|
1984
|
-
|
1985
|
-
|
2001
|
+
if limit
|
2002
|
+
args << "LIMIT"
|
2003
|
+
args.concat(limit)
|
2004
|
+
end
|
1986
2005
|
|
1987
2006
|
synchronize do |client|
|
1988
|
-
client.call(
|
2007
|
+
client.call(args, &block)
|
1989
2008
|
end
|
1990
2009
|
end
|
1991
2010
|
|
@@ -2005,7 +2024,7 @@ class Redis
|
|
2005
2024
|
# @param [String] max
|
2006
2025
|
# - inclusive maximum score is specified verbatim
|
2007
2026
|
# - exclusive maximum score is specified by prefixing `(`
|
2008
|
-
# @return [
|
2027
|
+
# @return [Integer] number of members that were removed
|
2009
2028
|
def zremrangebyscore(key, min, max)
|
2010
2029
|
synchronize do |client|
|
2011
2030
|
client.call([:zremrangebyscore, key, min, max])
|
@@ -2028,7 +2047,7 @@ class Redis
|
|
2028
2047
|
# @param [String] max
|
2029
2048
|
# - inclusive maximum score is specified verbatim
|
2030
2049
|
# - exclusive maximum score is specified by prefixing `(`
|
2031
|
-
# @return [
|
2050
|
+
# @return [Integer] number of members in within the specified range
|
2032
2051
|
def zcount(key, min, max)
|
2033
2052
|
synchronize do |client|
|
2034
2053
|
client.call([:zcount, key, min, max])
|
@@ -2048,18 +2067,19 @@ class Redis
|
|
2048
2067
|
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2049
2068
|
# sorted sets
|
2050
2069
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2051
|
-
# @return [
|
2052
|
-
def zinterstore(destination, keys,
|
2053
|
-
args = []
|
2070
|
+
# @return [Integer] number of elements in the resulting sorted set
|
2071
|
+
def zinterstore(destination, keys, weights: nil, aggregate: nil)
|
2072
|
+
args = [:zinterstore, destination, keys.size, *keys]
|
2054
2073
|
|
2055
|
-
|
2056
|
-
|
2074
|
+
if weights
|
2075
|
+
args << "WEIGHTS"
|
2076
|
+
args.concat(weights)
|
2077
|
+
end
|
2057
2078
|
|
2058
|
-
aggregate
|
2059
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2079
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2060
2080
|
|
2061
2081
|
synchronize do |client|
|
2062
|
-
client.call(
|
2082
|
+
client.call(args)
|
2063
2083
|
end
|
2064
2084
|
end
|
2065
2085
|
|
@@ -2075,40 +2095,46 @@ class Redis
|
|
2075
2095
|
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2076
2096
|
# sorted sets
|
2077
2097
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2078
|
-
# @return [
|
2079
|
-
def zunionstore(destination, keys,
|
2080
|
-
args = []
|
2098
|
+
# @return [Integer] number of elements in the resulting sorted set
|
2099
|
+
def zunionstore(destination, keys, weights: nil, aggregate: nil)
|
2100
|
+
args = [:zunionstore, destination, keys.size, *keys]
|
2081
2101
|
|
2082
|
-
|
2083
|
-
|
2102
|
+
if weights
|
2103
|
+
args << "WEIGHTS"
|
2104
|
+
args.concat(weights)
|
2105
|
+
end
|
2084
2106
|
|
2085
|
-
aggregate
|
2086
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2107
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2087
2108
|
|
2088
2109
|
synchronize do |client|
|
2089
|
-
client.call(
|
2110
|
+
client.call(args)
|
2090
2111
|
end
|
2091
2112
|
end
|
2092
2113
|
|
2093
2114
|
# Get the number of fields in a hash.
|
2094
2115
|
#
|
2095
2116
|
# @param [String] key
|
2096
|
-
# @return [
|
2117
|
+
# @return [Integer] number of fields in the hash
|
2097
2118
|
def hlen(key)
|
2098
2119
|
synchronize do |client|
|
2099
2120
|
client.call([:hlen, key])
|
2100
2121
|
end
|
2101
2122
|
end
|
2102
2123
|
|
2103
|
-
# Set
|
2124
|
+
# Set one or more hash values.
|
2125
|
+
#
|
2126
|
+
# @example
|
2127
|
+
# redis.hset("hash", "f1", "v1", "f2", "v2") # => 2
|
2128
|
+
# redis.hset("hash", { "f1" => "v1", "f2" => "v2" }) # => 2
|
2104
2129
|
#
|
2105
2130
|
# @param [String] key
|
2106
|
-
# @param [String]
|
2107
|
-
# @
|
2108
|
-
|
2109
|
-
|
2131
|
+
# @param [Array<String> | Hash<String, String>] attrs array or hash of fields and values
|
2132
|
+
# @return [Integer] The number of fields that were added to the hash
|
2133
|
+
def hset(key, *attrs)
|
2134
|
+
attrs = attrs.first.flatten if attrs.size == 1 && attrs.first.is_a?(Hash)
|
2135
|
+
|
2110
2136
|
synchronize do |client|
|
2111
|
-
client.call([:hset, key,
|
2137
|
+
client.call([:hset, key, *attrs])
|
2112
2138
|
end
|
2113
2139
|
end
|
2114
2140
|
|
@@ -2197,7 +2223,7 @@ class Redis
|
|
2197
2223
|
# @see #hmget
|
2198
2224
|
def mapped_hmget(key, *fields)
|
2199
2225
|
hmget(key, *fields) do |reply|
|
2200
|
-
if reply.
|
2226
|
+
if reply.is_a?(Array)
|
2201
2227
|
Hash[fields.zip(reply)]
|
2202
2228
|
else
|
2203
2229
|
reply
|
@@ -2209,7 +2235,7 @@ class Redis
|
|
2209
2235
|
#
|
2210
2236
|
# @param [String] key
|
2211
2237
|
# @param [String, Array<String>] field
|
2212
|
-
# @return [
|
2238
|
+
# @return [Integer] the number of fields that were removed from the hash
|
2213
2239
|
def hdel(key, *fields)
|
2214
2240
|
synchronize do |client|
|
2215
2241
|
client.call([:hdel, key, *fields])
|
@@ -2231,8 +2257,8 @@ class Redis
|
|
2231
2257
|
#
|
2232
2258
|
# @param [String] key
|
2233
2259
|
# @param [String] field
|
2234
|
-
# @param [
|
2235
|
-
# @return [
|
2260
|
+
# @param [Integer] increment
|
2261
|
+
# @return [Integer] value of the field after incrementing it
|
2236
2262
|
def hincrby(key, field, increment)
|
2237
2263
|
synchronize do |client|
|
2238
2264
|
client.call([:hincrby, key, field, increment])
|
@@ -2290,20 +2316,21 @@ class Redis
|
|
2290
2316
|
|
2291
2317
|
def subscribed?
|
2292
2318
|
synchronize do |client|
|
2293
|
-
client.
|
2319
|
+
client.is_a? SubscribedClient
|
2294
2320
|
end
|
2295
2321
|
end
|
2296
2322
|
|
2297
2323
|
# Listen for messages published to the given channels.
|
2298
2324
|
def subscribe(*channels, &block)
|
2299
|
-
synchronize do |
|
2325
|
+
synchronize do |_client|
|
2300
2326
|
_subscription(:subscribe, 0, channels, block)
|
2301
2327
|
end
|
2302
2328
|
end
|
2303
2329
|
|
2304
|
-
# Listen for messages published to the given channels. Throw a timeout error
|
2330
|
+
# Listen for messages published to the given channels. Throw a timeout error
|
2331
|
+
# if there is no messages for a timeout period.
|
2305
2332
|
def subscribe_with_timeout(timeout, *channels, &block)
|
2306
|
-
synchronize do |
|
2333
|
+
synchronize do |_client|
|
2307
2334
|
_subscription(:subscribe_with_timeout, timeout, channels, block)
|
2308
2335
|
end
|
2309
2336
|
end
|
@@ -2311,21 +2338,23 @@ class Redis
|
|
2311
2338
|
# Stop listening for messages posted to the given channels.
|
2312
2339
|
def unsubscribe(*channels)
|
2313
2340
|
synchronize do |client|
|
2314
|
-
raise
|
2341
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2342
|
+
|
2315
2343
|
client.unsubscribe(*channels)
|
2316
2344
|
end
|
2317
2345
|
end
|
2318
2346
|
|
2319
2347
|
# Listen for messages published to channels matching the given patterns.
|
2320
2348
|
def psubscribe(*channels, &block)
|
2321
|
-
synchronize do |
|
2349
|
+
synchronize do |_client|
|
2322
2350
|
_subscription(:psubscribe, 0, channels, block)
|
2323
2351
|
end
|
2324
2352
|
end
|
2325
2353
|
|
2326
|
-
# Listen for messages published to channels matching the given patterns.
|
2354
|
+
# Listen for messages published to channels matching the given patterns.
|
2355
|
+
# Throw a timeout error if there is no messages for a timeout period.
|
2327
2356
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
2328
|
-
synchronize do |
|
2357
|
+
synchronize do |_client|
|
2329
2358
|
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
2330
2359
|
end
|
2331
2360
|
end
|
@@ -2333,7 +2362,8 @@ class Redis
|
|
2333
2362
|
# Stop listening for messages posted to channels matching the given patterns.
|
2334
2363
|
def punsubscribe(*channels)
|
2335
2364
|
synchronize do |client|
|
2336
|
-
raise
|
2365
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2366
|
+
|
2337
2367
|
client.punsubscribe(*channels)
|
2338
2368
|
end
|
2339
2369
|
end
|
@@ -2378,7 +2408,7 @@ class Redis
|
|
2378
2408
|
# @see #multi
|
2379
2409
|
def watch(*keys)
|
2380
2410
|
synchronize do |client|
|
2381
|
-
res = client.call([:watch
|
2411
|
+
res = client.call([:watch, *keys])
|
2382
2412
|
|
2383
2413
|
if block_given?
|
2384
2414
|
begin
|
@@ -2408,7 +2438,7 @@ class Redis
|
|
2408
2438
|
end
|
2409
2439
|
|
2410
2440
|
def pipelined
|
2411
|
-
synchronize do |
|
2441
|
+
synchronize do |_client|
|
2412
2442
|
begin
|
2413
2443
|
pipeline = Pipeline.new(@client)
|
2414
2444
|
original, @client = @client, pipeline
|
@@ -2608,18 +2638,12 @@ class Redis
|
|
2608
2638
|
_eval(:evalsha, args)
|
2609
2639
|
end
|
2610
2640
|
|
2611
|
-
def _scan(command, cursor, args,
|
2641
|
+
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2612
2642
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2613
2643
|
|
2614
2644
|
args << cursor
|
2615
|
-
|
2616
|
-
|
2617
|
-
args.concat(["MATCH", match])
|
2618
|
-
end
|
2619
|
-
|
2620
|
-
if count = options[:count]
|
2621
|
-
args.concat(["COUNT", count])
|
2622
|
-
end
|
2645
|
+
args << "MATCH" << match if match
|
2646
|
+
args << "COUNT" << count if count
|
2623
2647
|
|
2624
2648
|
synchronize do |client|
|
2625
2649
|
client.call([command] + args, &block)
|
@@ -2641,8 +2665,8 @@ class Redis
|
|
2641
2665
|
# - `:count => Integer`: return count keys at most per iteration
|
2642
2666
|
#
|
2643
2667
|
# @return [String, Array<String>] the next cursor and all found keys
|
2644
|
-
def scan(cursor, options
|
2645
|
-
_scan(:scan, cursor, [], options)
|
2668
|
+
def scan(cursor, **options)
|
2669
|
+
_scan(:scan, cursor, [], **options)
|
2646
2670
|
end
|
2647
2671
|
|
2648
2672
|
# Scan the keyspace
|
@@ -2660,11 +2684,12 @@ class Redis
|
|
2660
2684
|
# - `:count => Integer`: return count keys at most per iteration
|
2661
2685
|
#
|
2662
2686
|
# @return [Enumerator] an enumerator for all found keys
|
2663
|
-
def scan_each(options
|
2664
|
-
return to_enum(:scan_each, options) unless block_given?
|
2687
|
+
def scan_each(**options, &block)
|
2688
|
+
return to_enum(:scan_each, **options) unless block_given?
|
2689
|
+
|
2665
2690
|
cursor = 0
|
2666
2691
|
loop do
|
2667
|
-
cursor, keys = scan(cursor, options)
|
2692
|
+
cursor, keys = scan(cursor, **options)
|
2668
2693
|
keys.each(&block)
|
2669
2694
|
break if cursor == "0"
|
2670
2695
|
end
|
@@ -2681,8 +2706,8 @@ class Redis
|
|
2681
2706
|
# - `:count => Integer`: return count keys at most per iteration
|
2682
2707
|
#
|
2683
2708
|
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
2684
|
-
def hscan(key, cursor, options
|
2685
|
-
_scan(:hscan, cursor, [key], options) do |reply|
|
2709
|
+
def hscan(key, cursor, **options)
|
2710
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2686
2711
|
[reply[0], reply[1].each_slice(2).to_a]
|
2687
2712
|
end
|
2688
2713
|
end
|
@@ -2698,11 +2723,12 @@ class Redis
|
|
2698
2723
|
# - `:count => Integer`: return count keys at most per iteration
|
2699
2724
|
#
|
2700
2725
|
# @return [Enumerator] an enumerator for all found keys
|
2701
|
-
def hscan_each(key, options
|
2702
|
-
return to_enum(:hscan_each, key, options) unless block_given?
|
2726
|
+
def hscan_each(key, **options, &block)
|
2727
|
+
return to_enum(:hscan_each, key, **options) unless block_given?
|
2728
|
+
|
2703
2729
|
cursor = 0
|
2704
2730
|
loop do
|
2705
|
-
cursor, values = hscan(key, cursor, options)
|
2731
|
+
cursor, values = hscan(key, cursor, **options)
|
2706
2732
|
values.each(&block)
|
2707
2733
|
break if cursor == "0"
|
2708
2734
|
end
|
@@ -2720,8 +2746,8 @@ class Redis
|
|
2720
2746
|
#
|
2721
2747
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2722
2748
|
# members and scores
|
2723
|
-
def zscan(key, cursor, options
|
2724
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2749
|
+
def zscan(key, cursor, **options)
|
2750
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2725
2751
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2726
2752
|
end
|
2727
2753
|
end
|
@@ -2737,11 +2763,12 @@ class Redis
|
|
2737
2763
|
# - `:count => Integer`: return count keys at most per iteration
|
2738
2764
|
#
|
2739
2765
|
# @return [Enumerator] an enumerator for all found scores and members
|
2740
|
-
def zscan_each(key, options
|
2741
|
-
return to_enum(:zscan_each, key, options) unless block_given?
|
2766
|
+
def zscan_each(key, **options, &block)
|
2767
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
2768
|
+
|
2742
2769
|
cursor = 0
|
2743
2770
|
loop do
|
2744
|
-
cursor, values = zscan(key, cursor, options)
|
2771
|
+
cursor, values = zscan(key, cursor, **options)
|
2745
2772
|
values.each(&block)
|
2746
2773
|
break if cursor == "0"
|
2747
2774
|
end
|
@@ -2758,8 +2785,8 @@ class Redis
|
|
2758
2785
|
# - `:count => Integer`: return count keys at most per iteration
|
2759
2786
|
#
|
2760
2787
|
# @return [String, Array<String>] the next cursor and all found members
|
2761
|
-
def sscan(key, cursor, options
|
2762
|
-
_scan(:sscan, cursor, [key], options)
|
2788
|
+
def sscan(key, cursor, **options)
|
2789
|
+
_scan(:sscan, cursor, [key], **options)
|
2763
2790
|
end
|
2764
2791
|
|
2765
2792
|
# Scan a set
|
@@ -2773,11 +2800,12 @@ class Redis
|
|
2773
2800
|
# - `:count => Integer`: return count keys at most per iteration
|
2774
2801
|
#
|
2775
2802
|
# @return [Enumerator] an enumerator for all keys in the set
|
2776
|
-
def sscan_each(key, options
|
2777
|
-
return to_enum(:sscan_each, key, options) unless block_given?
|
2803
|
+
def sscan_each(key, **options, &block)
|
2804
|
+
return to_enum(:sscan_each, key, **options) unless block_given?
|
2805
|
+
|
2778
2806
|
cursor = 0
|
2779
2807
|
loop do
|
2780
|
-
cursor, keys = sscan(key, cursor, options)
|
2808
|
+
cursor, keys = sscan(key, cursor, **options)
|
2781
2809
|
keys.each(&block)
|
2782
2810
|
break if cursor == "0"
|
2783
2811
|
end
|
@@ -2800,7 +2828,7 @@ class Redis
|
|
2800
2828
|
# union of the HyperLogLogs contained in the keys.
|
2801
2829
|
#
|
2802
2830
|
# @param [String, Array<String>] keys
|
2803
|
-
# @return [
|
2831
|
+
# @return [Integer]
|
2804
2832
|
def pfcount(*keys)
|
2805
2833
|
synchronize do |client|
|
2806
2834
|
client.call([:pfcount] + keys)
|
@@ -2841,12 +2869,12 @@ class Redis
|
|
2841
2869
|
end
|
2842
2870
|
end
|
2843
2871
|
|
2844
|
-
|
2845
2872
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2846
2873
|
# given maximum distance from a point
|
2847
2874
|
#
|
2848
2875
|
# @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
|
2849
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2876
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2877
|
+
# or the farthest to the nearest relative to the center
|
2850
2878
|
# @param [Integer] count limit the results to the first N matching items
|
2851
2879
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2852
2880
|
# @return [Array<String>] may be changed with `options`
|
@@ -2863,7 +2891,8 @@ class Redis
|
|
2863
2891
|
# given maximum distance from an already existing member
|
2864
2892
|
#
|
2865
2893
|
# @param [Array] args key, member, radius, unit(m|km|ft|mi)
|
2866
|
-
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2894
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2895
|
+
# to the nearest relative to the center
|
2867
2896
|
# @param [Integer] count limit the results to the first N matching items
|
2868
2897
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2869
2898
|
# @return [Array<String>] may be changed with `options`
|
@@ -2880,7 +2909,8 @@ class Redis
|
|
2880
2909
|
#
|
2881
2910
|
# @param [String] key
|
2882
2911
|
# @param [String, Array<String>] member one member or array of members
|
2883
|
-
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2912
|
+
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2913
|
+
# element is either array of longitude and latitude or nil
|
2884
2914
|
def geopos(key, member)
|
2885
2915
|
synchronize do |client|
|
2886
2916
|
client.call([:geopos, key, member])
|
@@ -2944,10 +2974,14 @@ class Redis
|
|
2944
2974
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2945
2975
|
#
|
2946
2976
|
# @return [String] the entry id
|
2947
|
-
def xadd(key, entry,
|
2977
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2948
2978
|
args = [:xadd, key]
|
2949
|
-
|
2950
|
-
|
2979
|
+
if maxlen
|
2980
|
+
args << "MAXLEN"
|
2981
|
+
args << "~" if approximate
|
2982
|
+
args << maxlen
|
2983
|
+
end
|
2984
|
+
args << id
|
2951
2985
|
args.concat(entry.to_a.flatten)
|
2952
2986
|
synchronize { |client| client.call(args) }
|
2953
2987
|
end
|
@@ -3002,8 +3036,8 @@ class Redis
|
|
3002
3036
|
# @param count [Integer] the number of entries as limit
|
3003
3037
|
#
|
3004
3038
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3005
|
-
def xrange(key, start = '-',
|
3006
|
-
args = [:xrange, key, start,
|
3039
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3040
|
+
args = [:xrange, key, start, range_end]
|
3007
3041
|
args.concat(['COUNT', count]) if count
|
3008
3042
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3009
3043
|
end
|
@@ -3025,8 +3059,8 @@ class Redis
|
|
3025
3059
|
# @params count [Integer] the number of entries as limit
|
3026
3060
|
#
|
3027
3061
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3028
|
-
def xrevrange(key,
|
3029
|
-
args = [:xrevrange, key,
|
3062
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3063
|
+
args = [:xrevrange, key, range_end, start]
|
3030
3064
|
args.concat(['COUNT', count]) if count
|
3031
3065
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3032
3066
|
end
|
@@ -3118,12 +3152,12 @@ class Redis
|
|
3118
3152
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3119
3153
|
#
|
3120
3154
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3121
|
-
def xreadgroup(group, consumer, keys, ids,
|
3155
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3122
3156
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3123
|
-
args << 'COUNT' <<
|
3124
|
-
args << 'BLOCK' <<
|
3125
|
-
args << 'NOACK' if
|
3126
|
-
_xread(args, keys, ids,
|
3157
|
+
args << 'COUNT' << count if count
|
3158
|
+
args << 'BLOCK' << block.to_i if block
|
3159
|
+
args << 'NOACK' if noack
|
3160
|
+
_xread(args, keys, ids, block)
|
3127
3161
|
end
|
3128
3162
|
|
3129
3163
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3233,8 +3267,8 @@ class Redis
|
|
3233
3267
|
when "get-master-addr-by-name"
|
3234
3268
|
reply
|
3235
3269
|
else
|
3236
|
-
if reply.
|
3237
|
-
if reply[0].
|
3270
|
+
if reply.is_a?(Array)
|
3271
|
+
if reply[0].is_a?(Array)
|
3238
3272
|
reply.map(&Hashify)
|
3239
3273
|
else
|
3240
3274
|
Hashify.call(reply)
|
@@ -3258,12 +3292,17 @@ class Redis
|
|
3258
3292
|
def cluster(subcommand, *args)
|
3259
3293
|
subcommand = subcommand.to_s.downcase
|
3260
3294
|
block = case subcommand
|
3261
|
-
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3295
|
+
when 'slots'
|
3296
|
+
HashifyClusterSlots
|
3297
|
+
when 'nodes'
|
3298
|
+
HashifyClusterNodes
|
3299
|
+
when 'slaves'
|
3300
|
+
HashifyClusterSlaves
|
3301
|
+
when 'info'
|
3302
|
+
HashifyInfo
|
3303
|
+
else
|
3304
|
+
Noop
|
3305
|
+
end
|
3267
3306
|
|
3268
3307
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3269
3308
|
block = Noop unless @cluster_mode
|
@@ -3298,21 +3337,21 @@ class Redis
|
|
3298
3337
|
return @original_client.connection_info if @cluster_mode
|
3299
3338
|
|
3300
3339
|
{
|
3301
|
-
host:
|
3302
|
-
port:
|
3303
|
-
db:
|
3304
|
-
id:
|
3340
|
+
host: @original_client.host,
|
3341
|
+
port: @original_client.port,
|
3342
|
+
db: @original_client.db,
|
3343
|
+
id: @original_client.id,
|
3305
3344
|
location: @original_client.location
|
3306
3345
|
}
|
3307
3346
|
end
|
3308
3347
|
|
3309
|
-
def method_missing(command, *args)
|
3348
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3310
3349
|
synchronize do |client|
|
3311
3350
|
client.call([command] + args)
|
3312
3351
|
end
|
3313
3352
|
end
|
3314
3353
|
|
3315
|
-
private
|
3354
|
+
private
|
3316
3355
|
|
3317
3356
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3318
3357
|
# where the method call will return nil. Propagate the nil instead of falsely
|
@@ -3384,18 +3423,21 @@ private
|
|
3384
3423
|
end
|
3385
3424
|
}
|
3386
3425
|
|
3426
|
+
EMPTY_STREAM_RESPONSE = [nil].freeze
|
3427
|
+
private_constant :EMPTY_STREAM_RESPONSE
|
3428
|
+
|
3387
3429
|
HashifyStreamEntries = lambda { |reply|
|
3388
|
-
reply.map do |entry_id, values|
|
3430
|
+
reply.compact.map do |entry_id, values|
|
3389
3431
|
[entry_id, values.each_slice(2).to_h]
|
3390
3432
|
end
|
3391
3433
|
}
|
3392
3434
|
|
3393
3435
|
HashifyStreamPendings = lambda { |reply|
|
3394
3436
|
{
|
3395
|
-
'size'
|
3437
|
+
'size' => reply[0],
|
3396
3438
|
'min_entry_id' => reply[1],
|
3397
3439
|
'max_entry_id' => reply[2],
|
3398
|
-
'consumers'
|
3440
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3399
3441
|
}
|
3400
3442
|
}
|
3401
3443
|
|
@@ -3404,8 +3446,8 @@ private
|
|
3404
3446
|
{
|
3405
3447
|
'entry_id' => arr[0],
|
3406
3448
|
'consumer' => arr[1],
|
3407
|
-
'elapsed'
|
3408
|
-
'count'
|
3449
|
+
'elapsed' => arr[2],
|
3450
|
+
'count' => arr[3]
|
3409
3451
|
}
|
3410
3452
|
end
|
3411
3453
|
}
|
@@ -3413,15 +3455,15 @@ private
|
|
3413
3455
|
HashifyClusterNodeInfo = lambda { |str|
|
3414
3456
|
arr = str.split(' ')
|
3415
3457
|
{
|
3416
|
-
'node_id'
|
3417
|
-
'ip_port'
|
3418
|
-
'flags'
|
3458
|
+
'node_id' => arr[0],
|
3459
|
+
'ip_port' => arr[1],
|
3460
|
+
'flags' => arr[2].split(','),
|
3419
3461
|
'master_node_id' => arr[3],
|
3420
|
-
'ping_sent'
|
3421
|
-
'pong_recv'
|
3422
|
-
'config_epoch'
|
3423
|
-
'link_state'
|
3424
|
-
'slots'
|
3462
|
+
'ping_sent' => arr[4],
|
3463
|
+
'pong_recv' => arr[5],
|
3464
|
+
'config_epoch' => arr[6],
|
3465
|
+
'link_state' => arr[7],
|
3466
|
+
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3425
3467
|
}
|
3426
3468
|
}
|
3427
3469
|
|
@@ -3432,9 +3474,9 @@ private
|
|
3432
3474
|
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3433
3475
|
{
|
3434
3476
|
'start_slot' => first_slot,
|
3435
|
-
'end_slot'
|
3436
|
-
'master'
|
3437
|
-
'replicas'
|
3477
|
+
'end_slot' => last_slot,
|
3478
|
+
'master' => master,
|
3479
|
+
'replicas' => replicas
|
3438
3480
|
}
|
3439
3481
|
end
|
3440
3482
|
}
|