redis 4.1.4 → 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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +8 -4
- data/lib/redis.rb +255 -237
- data/lib/redis/client.rb +66 -70
- data/lib/redis/cluster.rb +4 -0
- data/lib/redis/cluster/node.rb +3 -0
- data/lib/redis/cluster/option.rb +4 -1
- data/lib/redis/cluster/slot.rb +28 -14
- data/lib/redis/cluster/slot_loader.rb +2 -3
- data/lib/redis/connection.rb +1 -0
- data/lib/redis/connection/command_helper.rb +2 -2
- data/lib/redis/connection/hiredis.rb +3 -3
- data/lib/redis/connection/registry.rb +1 -1
- data/lib/redis/connection/ruby.rb +38 -61
- data/lib/redis/connection/synchrony.rb +8 -4
- data/lib/redis/distributed.rb +72 -50
- data/lib/redis/errors.rb +1 -0
- data/lib/redis/hash_ring.rb +14 -14
- data/lib/redis/pipeline.rb +6 -8
- data/lib/redis/subscribe.rb +10 -12
- data/lib/redis/version.rb +2 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
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,18 @@
|
|
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
|
+
|
3
16
|
# 4.1.4
|
4
17
|
|
5
18
|
* Alias `Redis#disconnect` as `#close`. See #901.
|
@@ -9,6 +22,7 @@
|
|
9
22
|
* Increase buffer size in the ruby connector. See #880.
|
10
23
|
* Fix thread safety of `Redis.queue`. See #878.
|
11
24
|
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
25
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
12
26
|
|
13
27
|
# 4.1.3
|
14
28
|
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
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.
|
@@ -147,8 +151,8 @@ redis.mget('{key}1', '{key}2')
|
|
147
151
|
|
148
152
|
## Storing objects
|
149
153
|
|
150
|
-
Redis
|
151
|
-
|
154
|
+
Redis "string" types can be used to store serialized Ruby objects, for
|
155
|
+
example with JSON:
|
152
156
|
|
153
157
|
```ruby
|
154
158
|
require "json"
|
@@ -322,7 +326,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
322
326
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
323
327
|
or [ghostunnel].
|
324
328
|
|
325
|
-
To enable SSL support, pass the `:ssl =>
|
329
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
326
330
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
327
331
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
328
332
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -451,7 +455,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
451
455
|
## Contributing
|
452
456
|
|
453
457
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
454
|
-
requests.
|
458
|
+
requests.
|
455
459
|
|
456
460
|
|
457
461
|
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
data/lib/redis.rb
CHANGED
@@ -4,12 +4,13 @@ require "monitor"
|
|
4
4
|
require_relative "redis/errors"
|
5
5
|
|
6
6
|
class Redis
|
7
|
-
|
8
|
-
|
7
|
+
class << self
|
8
|
+
attr_accessor :exists_returns_integer
|
9
|
+
attr_writer :current
|
9
10
|
end
|
10
11
|
|
11
|
-
def self.current
|
12
|
-
@current
|
12
|
+
def self.current
|
13
|
+
@current ||= Redis.new
|
13
14
|
end
|
14
15
|
|
15
16
|
include MonitorMixin
|
@@ -17,7 +18,9 @@ class Redis
|
|
17
18
|
# Create a new client instance
|
18
19
|
#
|
19
20
|
# @param [Hash] options
|
20
|
-
# @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.
|
21
24
|
# @option options [String] :host ("127.0.0.1") server hostname
|
22
25
|
# @option options [Integer] :port (6379) server port
|
23
26
|
# @option options [String] :path path to server socket (overrides host and port)
|
@@ -26,8 +29,10 @@ class Redis
|
|
26
29
|
# @option options [String] :password Password to authenticate against server
|
27
30
|
# @option options [Integer] :db (0) Database to select after initial connect
|
28
31
|
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
29
|
-
# @option options [String] :id ID for the client connection, assigns name to current connection by sending
|
30
|
-
#
|
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
|
31
36
|
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
32
37
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
33
38
|
# @option options [Array] :sentinels List of sentinels to contact
|
@@ -52,7 +57,7 @@ class Redis
|
|
52
57
|
end
|
53
58
|
|
54
59
|
# Run code with the client reconnecting
|
55
|
-
def with_reconnect(val=true, &blk)
|
60
|
+
def with_reconnect(val = true, &blk)
|
56
61
|
synchronize do |client|
|
57
62
|
client.with_reconnect(val, &blk)
|
58
63
|
end
|
@@ -205,7 +210,7 @@ class Redis
|
|
205
210
|
def config(action, *args)
|
206
211
|
synchronize do |client|
|
207
212
|
client.call([:config, action] + args) do |reply|
|
208
|
-
if reply.
|
213
|
+
if reply.is_a?(Array) && action == :get
|
209
214
|
Hashify.call(reply)
|
210
215
|
else
|
211
216
|
reply
|
@@ -256,7 +261,7 @@ class Redis
|
|
256
261
|
def flushall(options = nil)
|
257
262
|
synchronize do |client|
|
258
263
|
if options && options[:async]
|
259
|
-
client.call([
|
264
|
+
client.call(%i[flushall async])
|
260
265
|
else
|
261
266
|
client.call([:flushall])
|
262
267
|
end
|
@@ -271,7 +276,7 @@ class Redis
|
|
271
276
|
def flushdb(options = nil)
|
272
277
|
synchronize do |client|
|
273
278
|
if options && options[:async]
|
274
|
-
client.call([
|
279
|
+
client.call(%i[flushdb async])
|
275
280
|
else
|
276
281
|
client.call([:flushdb])
|
277
282
|
end
|
@@ -285,7 +290,7 @@ class Redis
|
|
285
290
|
def info(cmd = nil)
|
286
291
|
synchronize do |client|
|
287
292
|
client.call([:info, cmd].compact) do |reply|
|
288
|
-
if reply.
|
293
|
+
if reply.is_a?(String)
|
289
294
|
reply = HashifyInfo.call(reply)
|
290
295
|
|
291
296
|
if cmd && cmd.to_s == "commandstats"
|
@@ -358,7 +363,7 @@ class Redis
|
|
358
363
|
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
359
364
|
# @param [Integer] length maximum number of entries to return
|
360
365
|
# @return [Array<String>, Integer, String] depends on subcommand
|
361
|
-
def slowlog(subcommand, length=nil)
|
366
|
+
def slowlog(subcommand, length = nil)
|
362
367
|
synchronize do |client|
|
363
368
|
args = [:slowlog, subcommand]
|
364
369
|
args << length if length
|
@@ -383,7 +388,7 @@ class Redis
|
|
383
388
|
def time
|
384
389
|
synchronize do |client|
|
385
390
|
client.call([:time]) do |reply|
|
386
|
-
reply
|
391
|
+
reply&.map(&:to_i)
|
387
392
|
end
|
388
393
|
end
|
389
394
|
end
|
@@ -496,9 +501,9 @@ class Redis
|
|
496
501
|
# - `:replace => Boolean`: if false, raises an error if key already exists
|
497
502
|
# @raise [Redis::CommandError]
|
498
503
|
# @return [String] `"OK"`
|
499
|
-
def restore(key, ttl, serialized_value,
|
504
|
+
def restore(key, ttl, serialized_value, replace: nil)
|
500
505
|
args = [:restore, key, ttl, serialized_value]
|
501
|
-
args << 'REPLACE' if
|
506
|
+
args << 'REPLACE' if replace
|
502
507
|
|
503
508
|
synchronize do |client|
|
504
509
|
client.call(args)
|
@@ -550,13 +555,36 @@ class Redis
|
|
550
555
|
end
|
551
556
|
end
|
552
557
|
|
553
|
-
# Determine
|
558
|
+
# Determine how many of the keys exists.
|
554
559
|
#
|
555
|
-
# @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
|
556
584
|
# @return [Boolean]
|
557
|
-
def exists(
|
585
|
+
def exists?(*keys)
|
558
586
|
synchronize do |client|
|
559
|
-
client.call([:exists,
|
587
|
+
client.call([:exists, *keys], &Boolify)
|
560
588
|
end
|
561
589
|
end
|
562
590
|
|
@@ -567,7 +595,7 @@ class Redis
|
|
567
595
|
def keys(pattern = "*")
|
568
596
|
synchronize do |client|
|
569
597
|
client.call([:keys, pattern]) do |reply|
|
570
|
-
if reply.
|
598
|
+
if reply.is_a?(String)
|
571
599
|
reply.split(" ")
|
572
600
|
else
|
573
601
|
reply
|
@@ -663,30 +691,27 @@ class Redis
|
|
663
691
|
# elements where every element is an array with the result for every
|
664
692
|
# element specified in `:get`
|
665
693
|
# - when `:store` is specified, the number of elements in the stored result
|
666
|
-
def sort(key,
|
667
|
-
args = []
|
668
|
-
|
669
|
-
by = options[:by]
|
670
|
-
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
|
671
697
|
|
672
|
-
|
673
|
-
|
698
|
+
if limit
|
699
|
+
args << "LIMIT"
|
700
|
+
args.concat(limit)
|
701
|
+
end
|
674
702
|
|
675
|
-
get = Array(
|
676
|
-
|
703
|
+
get = Array(get)
|
704
|
+
get.each do |item|
|
705
|
+
args << "GET" << item
|
706
|
+
end
|
677
707
|
|
678
|
-
order = options[:order]
|
679
708
|
args.concat(order.split(" ")) if order
|
680
|
-
|
681
|
-
store = options[:store]
|
682
|
-
args.concat(["STORE", store]) if store
|
709
|
+
args << "STORE" << store if store
|
683
710
|
|
684
711
|
synchronize do |client|
|
685
|
-
client.call(
|
712
|
+
client.call(args) do |reply|
|
686
713
|
if get.size > 1 && !store
|
687
|
-
if reply
|
688
|
-
reply.each_slice(get.size).to_a
|
689
|
-
end
|
714
|
+
reply.each_slice(get.size).to_a if reply
|
690
715
|
else
|
691
716
|
reply
|
692
717
|
end
|
@@ -786,27 +811,21 @@ class Redis
|
|
786
811
|
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
787
812
|
# - `:nx => true`: Only set the key if it does not already exist.
|
788
813
|
# - `:xx => true`: Only set the key if it already exist.
|
814
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
789
815
|
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
790
|
-
def set(key, value,
|
791
|
-
args = []
|
792
|
-
|
793
|
-
|
794
|
-
args
|
795
|
-
|
796
|
-
|
797
|
-
args.concat(["PX", px]) if px
|
798
|
-
|
799
|
-
nx = options[:nx]
|
800
|
-
args.concat(["NX"]) if nx
|
801
|
-
|
802
|
-
xx = options[:xx]
|
803
|
-
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
|
804
823
|
|
805
824
|
synchronize do |client|
|
806
825
|
if nx || xx
|
807
|
-
client.call(
|
826
|
+
client.call(args, &BoolifySet)
|
808
827
|
else
|
809
|
-
client.call(
|
828
|
+
client.call(args)
|
810
829
|
end
|
811
830
|
end
|
812
831
|
end
|
@@ -888,7 +907,7 @@ class Redis
|
|
888
907
|
# @see #mapped_msetnx
|
889
908
|
def msetnx(*args)
|
890
909
|
synchronize do |client|
|
891
|
-
client.call([:msetnx
|
910
|
+
client.call([:msetnx, *args], &Boolify)
|
892
911
|
end
|
893
912
|
end
|
894
913
|
|
@@ -928,7 +947,7 @@ class Redis
|
|
928
947
|
# @see #mapped_mget
|
929
948
|
def mget(*keys, &blk)
|
930
949
|
synchronize do |client|
|
931
|
-
client.call([:mget
|
950
|
+
client.call([:mget, *keys], &blk)
|
932
951
|
end
|
933
952
|
end
|
934
953
|
|
@@ -944,7 +963,7 @@ class Redis
|
|
944
963
|
# @see #mget
|
945
964
|
def mapped_mget(*keys)
|
946
965
|
mget(*keys) do |reply|
|
947
|
-
if reply.
|
966
|
+
if reply.is_a?(Array)
|
948
967
|
Hash[keys.zip(reply)]
|
949
968
|
else
|
950
969
|
reply
|
@@ -1031,7 +1050,7 @@ class Redis
|
|
1031
1050
|
# @return [Integer] the length of the string stored in `destkey`
|
1032
1051
|
def bitop(operation, destkey, *keys)
|
1033
1052
|
synchronize do |client|
|
1034
|
-
client.call([:bitop, operation, destkey
|
1053
|
+
client.call([:bitop, operation, destkey, *keys])
|
1035
1054
|
end
|
1036
1055
|
end
|
1037
1056
|
|
@@ -1043,10 +1062,8 @@ class Redis
|
|
1043
1062
|
# @param [Integer] stop stop index
|
1044
1063
|
# @return [Integer] the position of the first 1/0 bit.
|
1045
1064
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
1046
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
1047
|
-
|
1048
|
-
raise(ArgumentError, 'stop parameter specified without start parameter')
|
1049
|
-
end
|
1065
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
1066
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
1050
1067
|
|
1051
1068
|
synchronize do |client|
|
1052
1069
|
command = [:bitpos, key, bit]
|
@@ -1240,15 +1257,7 @@ class Redis
|
|
1240
1257
|
# @return [nil, String]
|
1241
1258
|
# - `nil` when the operation timed out
|
1242
1259
|
# - the element was popped and pushed otherwise
|
1243
|
-
def brpoplpush(source, destination,
|
1244
|
-
case options
|
1245
|
-
when Integer
|
1246
|
-
# Issue deprecation notice in obnoxious mode...
|
1247
|
-
options = { :timeout => options }
|
1248
|
-
end
|
1249
|
-
|
1250
|
-
timeout = options[:timeout] || 0
|
1251
|
-
|
1260
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
|
1252
1261
|
synchronize do |client|
|
1253
1262
|
command = [:brpoplpush, source, destination, timeout]
|
1254
1263
|
timeout += client.timeout if timeout > 0
|
@@ -1455,7 +1464,7 @@ class Redis
|
|
1455
1464
|
# @return [Array<String>] members in the difference
|
1456
1465
|
def sdiff(*keys)
|
1457
1466
|
synchronize do |client|
|
1458
|
-
client.call([:sdiff
|
1467
|
+
client.call([:sdiff, *keys])
|
1459
1468
|
end
|
1460
1469
|
end
|
1461
1470
|
|
@@ -1466,7 +1475,7 @@ class Redis
|
|
1466
1475
|
# @return [Integer] number of elements in the resulting set
|
1467
1476
|
def sdiffstore(destination, *keys)
|
1468
1477
|
synchronize do |client|
|
1469
|
-
client.call([:sdiffstore, destination
|
1478
|
+
client.call([:sdiffstore, destination, *keys])
|
1470
1479
|
end
|
1471
1480
|
end
|
1472
1481
|
|
@@ -1476,7 +1485,7 @@ class Redis
|
|
1476
1485
|
# @return [Array<String>] members in the intersection
|
1477
1486
|
def sinter(*keys)
|
1478
1487
|
synchronize do |client|
|
1479
|
-
client.call([:sinter
|
1488
|
+
client.call([:sinter, *keys])
|
1480
1489
|
end
|
1481
1490
|
end
|
1482
1491
|
|
@@ -1487,7 +1496,7 @@ class Redis
|
|
1487
1496
|
# @return [Integer] number of elements in the resulting set
|
1488
1497
|
def sinterstore(destination, *keys)
|
1489
1498
|
synchronize do |client|
|
1490
|
-
client.call([:sinterstore, destination
|
1499
|
+
client.call([:sinterstore, destination, *keys])
|
1491
1500
|
end
|
1492
1501
|
end
|
1493
1502
|
|
@@ -1497,7 +1506,7 @@ class Redis
|
|
1497
1506
|
# @return [Array<String>] members in the union
|
1498
1507
|
def sunion(*keys)
|
1499
1508
|
synchronize do |client|
|
1500
|
-
client.call([:sunion
|
1509
|
+
client.call([:sunion, *keys])
|
1501
1510
|
end
|
1502
1511
|
end
|
1503
1512
|
|
@@ -1508,7 +1517,7 @@ class Redis
|
|
1508
1517
|
# @return [Integer] number of elements in the resulting set
|
1509
1518
|
def sunionstore(destination, *keys)
|
1510
1519
|
synchronize do |client|
|
1511
|
-
client.call([:sunionstore, destination
|
1520
|
+
client.call([:sunionstore, destination, *keys])
|
1512
1521
|
end
|
1513
1522
|
end
|
1514
1523
|
|
@@ -1557,31 +1566,20 @@ class Redis
|
|
1557
1566
|
# pairs that were **added** to the sorted set.
|
1558
1567
|
# - `Float` when option :incr is specified, holding the score of the member
|
1559
1568
|
# after incrementing it.
|
1560
|
-
def zadd(key, *args
|
1561
|
-
|
1562
|
-
if
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
zadd_options << "NX" if nx
|
1567
|
-
|
1568
|
-
xx = options[:xx]
|
1569
|
-
zadd_options << "XX" if xx
|
1570
|
-
|
1571
|
-
ch = options[:ch]
|
1572
|
-
zadd_options << "CH" if ch
|
1573
|
-
|
1574
|
-
incr = options[:incr]
|
1575
|
-
zadd_options << "INCR" if incr
|
1576
|
-
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
|
1577
1575
|
|
1578
1576
|
synchronize do |client|
|
1579
1577
|
if args.size == 1 && args[0].is_a?(Array)
|
1580
1578
|
# Variadic: return float if INCR, integer if !INCR
|
1581
|
-
client.call(
|
1579
|
+
client.call(command + args[0], &(incr ? Floatify : nil))
|
1582
1580
|
elsif args.size == 2
|
1583
1581
|
# Single pair: return float if INCR, boolean if !INCR
|
1584
|
-
client.call(
|
1582
|
+
client.call(command + args, &(incr ? Floatify : Boolify))
|
1585
1583
|
else
|
1586
1584
|
raise ArgumentError, "wrong number of arguments"
|
1587
1585
|
end
|
@@ -1752,10 +1750,8 @@ class Redis
|
|
1752
1750
|
# @return [Array<String>, Array<[String, Float]>]
|
1753
1751
|
# - when `:with_scores` is not specified, an array of members
|
1754
1752
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1755
|
-
def zrange(key, start, stop,
|
1756
|
-
args = []
|
1757
|
-
|
1758
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1753
|
+
def zrange(key, start, stop, withscores: false, with_scores: withscores)
|
1754
|
+
args = [:zrange, key, start, stop]
|
1759
1755
|
|
1760
1756
|
if with_scores
|
1761
1757
|
args << "WITHSCORES"
|
@@ -1763,7 +1759,7 @@ class Redis
|
|
1763
1759
|
end
|
1764
1760
|
|
1765
1761
|
synchronize do |client|
|
1766
|
-
client.call(
|
1762
|
+
client.call(args, &block)
|
1767
1763
|
end
|
1768
1764
|
end
|
1769
1765
|
|
@@ -1778,10 +1774,8 @@ class Redis
|
|
1778
1774
|
# # => [["b", 64.0], ["a", 32.0]]
|
1779
1775
|
#
|
1780
1776
|
# @see #zrange
|
1781
|
-
def zrevrange(key, start, stop,
|
1782
|
-
args = []
|
1783
|
-
|
1784
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1777
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
1778
|
+
args = [:zrevrange, key, start, stop]
|
1785
1779
|
|
1786
1780
|
if with_scores
|
1787
1781
|
args << "WITHSCORES"
|
@@ -1789,7 +1783,7 @@ class Redis
|
|
1789
1783
|
end
|
1790
1784
|
|
1791
1785
|
synchronize do |client|
|
1792
|
-
client.call(
|
1786
|
+
client.call(args, &block)
|
1793
1787
|
end
|
1794
1788
|
end
|
1795
1789
|
|
@@ -1880,14 +1874,16 @@ class Redis
|
|
1880
1874
|
# `count` members
|
1881
1875
|
#
|
1882
1876
|
# @return [Array<String>, Array<[String, Float]>]
|
1883
|
-
def zrangebylex(key, min, max,
|
1884
|
-
args = []
|
1877
|
+
def zrangebylex(key, min, max, limit: nil)
|
1878
|
+
args = [:zrangebylex, key, min, max]
|
1885
1879
|
|
1886
|
-
|
1887
|
-
|
1880
|
+
if limit
|
1881
|
+
args << "LIMIT"
|
1882
|
+
args.concat(limit)
|
1883
|
+
end
|
1888
1884
|
|
1889
1885
|
synchronize do |client|
|
1890
|
-
client.call(
|
1886
|
+
client.call(args)
|
1891
1887
|
end
|
1892
1888
|
end
|
1893
1889
|
|
@@ -1902,14 +1898,16 @@ class Redis
|
|
1902
1898
|
# # => ["abbygail", "abby"]
|
1903
1899
|
#
|
1904
1900
|
# @see #zrangebylex
|
1905
|
-
def zrevrangebylex(key, max, min,
|
1906
|
-
args = []
|
1901
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
1902
|
+
args = [:zrevrangebylex, key, max, min]
|
1907
1903
|
|
1908
|
-
|
1909
|
-
|
1904
|
+
if limit
|
1905
|
+
args << "LIMIT"
|
1906
|
+
args.concat(limit)
|
1907
|
+
end
|
1910
1908
|
|
1911
1909
|
synchronize do |client|
|
1912
|
-
client.call(
|
1910
|
+
client.call(args)
|
1913
1911
|
end
|
1914
1912
|
end
|
1915
1913
|
|
@@ -1940,21 +1938,21 @@ class Redis
|
|
1940
1938
|
# @return [Array<String>, Array<[String, Float]>]
|
1941
1939
|
# - when `:with_scores` is not specified, an array of members
|
1942
1940
|
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
1943
|
-
def zrangebyscore(key, min, max,
|
1944
|
-
args = []
|
1945
|
-
|
1946
|
-
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]
|
1947
1943
|
|
1948
1944
|
if with_scores
|
1949
1945
|
args << "WITHSCORES"
|
1950
1946
|
block = FloatifyPairs
|
1951
1947
|
end
|
1952
1948
|
|
1953
|
-
|
1954
|
-
|
1949
|
+
if limit
|
1950
|
+
args << "LIMIT"
|
1951
|
+
args.concat(limit)
|
1952
|
+
end
|
1955
1953
|
|
1956
1954
|
synchronize do |client|
|
1957
|
-
client.call(
|
1955
|
+
client.call(args, &block)
|
1958
1956
|
end
|
1959
1957
|
end
|
1960
1958
|
|
@@ -1972,21 +1970,21 @@ class Redis
|
|
1972
1970
|
# # => [["b", 64.0], ["a", 32.0]]
|
1973
1971
|
#
|
1974
1972
|
# @see #zrangebyscore
|
1975
|
-
def zrevrangebyscore(key, max, min,
|
1976
|
-
args = []
|
1977
|
-
|
1978
|
-
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]
|
1979
1975
|
|
1980
1976
|
if with_scores
|
1981
|
-
args <<
|
1977
|
+
args << "WITHSCORES"
|
1982
1978
|
block = FloatifyPairs
|
1983
1979
|
end
|
1984
1980
|
|
1985
|
-
|
1986
|
-
|
1981
|
+
if limit
|
1982
|
+
args << "LIMIT"
|
1983
|
+
args.concat(limit)
|
1984
|
+
end
|
1987
1985
|
|
1988
1986
|
synchronize do |client|
|
1989
|
-
client.call(
|
1987
|
+
client.call(args, &block)
|
1990
1988
|
end
|
1991
1989
|
end
|
1992
1990
|
|
@@ -2050,17 +2048,18 @@ class Redis
|
|
2050
2048
|
# sorted sets
|
2051
2049
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2052
2050
|
# @return [Integer] number of elements in the resulting sorted set
|
2053
|
-
def zinterstore(destination, keys,
|
2054
|
-
args = []
|
2051
|
+
def zinterstore(destination, keys, weights: nil, aggregate: nil)
|
2052
|
+
args = [:zinterstore, destination, keys.size, *keys]
|
2055
2053
|
|
2056
|
-
|
2057
|
-
|
2054
|
+
if weights
|
2055
|
+
args << "WEIGHTS"
|
2056
|
+
args.concat(weights)
|
2057
|
+
end
|
2058
2058
|
|
2059
|
-
aggregate
|
2060
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2059
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2061
2060
|
|
2062
2061
|
synchronize do |client|
|
2063
|
-
client.call(
|
2062
|
+
client.call(args)
|
2064
2063
|
end
|
2065
2064
|
end
|
2066
2065
|
|
@@ -2077,17 +2076,18 @@ class Redis
|
|
2077
2076
|
# sorted sets
|
2078
2077
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2079
2078
|
# @return [Integer] number of elements in the resulting sorted set
|
2080
|
-
def zunionstore(destination, keys,
|
2081
|
-
args = []
|
2079
|
+
def zunionstore(destination, keys, weights: nil, aggregate: nil)
|
2080
|
+
args = [:zunionstore, destination, keys.size, *keys]
|
2082
2081
|
|
2083
|
-
|
2084
|
-
|
2082
|
+
if weights
|
2083
|
+
args << "WEIGHTS"
|
2084
|
+
args.concat(weights)
|
2085
|
+
end
|
2085
2086
|
|
2086
|
-
aggregate
|
2087
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2087
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2088
2088
|
|
2089
2089
|
synchronize do |client|
|
2090
|
-
client.call(
|
2090
|
+
client.call(args)
|
2091
2091
|
end
|
2092
2092
|
end
|
2093
2093
|
|
@@ -2101,15 +2101,20 @@ class Redis
|
|
2101
2101
|
end
|
2102
2102
|
end
|
2103
2103
|
|
2104
|
-
# 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
|
2105
2109
|
#
|
2106
2110
|
# @param [String] key
|
2107
|
-
# @param [String]
|
2108
|
-
# @
|
2109
|
-
|
2110
|
-
|
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
|
+
|
2111
2116
|
synchronize do |client|
|
2112
|
-
client.call([:hset, key,
|
2117
|
+
client.call([:hset, key, *attrs])
|
2113
2118
|
end
|
2114
2119
|
end
|
2115
2120
|
|
@@ -2198,7 +2203,7 @@ class Redis
|
|
2198
2203
|
# @see #hmget
|
2199
2204
|
def mapped_hmget(key, *fields)
|
2200
2205
|
hmget(key, *fields) do |reply|
|
2201
|
-
if reply.
|
2206
|
+
if reply.is_a?(Array)
|
2202
2207
|
Hash[fields.zip(reply)]
|
2203
2208
|
else
|
2204
2209
|
reply
|
@@ -2291,20 +2296,21 @@ class Redis
|
|
2291
2296
|
|
2292
2297
|
def subscribed?
|
2293
2298
|
synchronize do |client|
|
2294
|
-
client.
|
2299
|
+
client.is_a? SubscribedClient
|
2295
2300
|
end
|
2296
2301
|
end
|
2297
2302
|
|
2298
2303
|
# Listen for messages published to the given channels.
|
2299
2304
|
def subscribe(*channels, &block)
|
2300
|
-
synchronize do |
|
2305
|
+
synchronize do |_client|
|
2301
2306
|
_subscription(:subscribe, 0, channels, block)
|
2302
2307
|
end
|
2303
2308
|
end
|
2304
2309
|
|
2305
|
-
# 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.
|
2306
2312
|
def subscribe_with_timeout(timeout, *channels, &block)
|
2307
|
-
synchronize do |
|
2313
|
+
synchronize do |_client|
|
2308
2314
|
_subscription(:subscribe_with_timeout, timeout, channels, block)
|
2309
2315
|
end
|
2310
2316
|
end
|
@@ -2312,21 +2318,23 @@ class Redis
|
|
2312
2318
|
# Stop listening for messages posted to the given channels.
|
2313
2319
|
def unsubscribe(*channels)
|
2314
2320
|
synchronize do |client|
|
2315
|
-
raise
|
2321
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2322
|
+
|
2316
2323
|
client.unsubscribe(*channels)
|
2317
2324
|
end
|
2318
2325
|
end
|
2319
2326
|
|
2320
2327
|
# Listen for messages published to channels matching the given patterns.
|
2321
2328
|
def psubscribe(*channels, &block)
|
2322
|
-
synchronize do |
|
2329
|
+
synchronize do |_client|
|
2323
2330
|
_subscription(:psubscribe, 0, channels, block)
|
2324
2331
|
end
|
2325
2332
|
end
|
2326
2333
|
|
2327
|
-
# 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.
|
2328
2336
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
2329
|
-
synchronize do |
|
2337
|
+
synchronize do |_client|
|
2330
2338
|
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
2331
2339
|
end
|
2332
2340
|
end
|
@@ -2334,7 +2342,8 @@ class Redis
|
|
2334
2342
|
# Stop listening for messages posted to channels matching the given patterns.
|
2335
2343
|
def punsubscribe(*channels)
|
2336
2344
|
synchronize do |client|
|
2337
|
-
raise
|
2345
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2346
|
+
|
2338
2347
|
client.punsubscribe(*channels)
|
2339
2348
|
end
|
2340
2349
|
end
|
@@ -2379,7 +2388,7 @@ class Redis
|
|
2379
2388
|
# @see #multi
|
2380
2389
|
def watch(*keys)
|
2381
2390
|
synchronize do |client|
|
2382
|
-
res = client.call([:watch
|
2391
|
+
res = client.call([:watch, *keys])
|
2383
2392
|
|
2384
2393
|
if block_given?
|
2385
2394
|
begin
|
@@ -2409,7 +2418,7 @@ class Redis
|
|
2409
2418
|
end
|
2410
2419
|
|
2411
2420
|
def pipelined
|
2412
|
-
synchronize do |
|
2421
|
+
synchronize do |_client|
|
2413
2422
|
begin
|
2414
2423
|
pipeline = Pipeline.new(@client)
|
2415
2424
|
original, @client = @client, pipeline
|
@@ -2609,18 +2618,12 @@ class Redis
|
|
2609
2618
|
_eval(:evalsha, args)
|
2610
2619
|
end
|
2611
2620
|
|
2612
|
-
def _scan(command, cursor, args,
|
2621
|
+
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2613
2622
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2614
2623
|
|
2615
2624
|
args << cursor
|
2616
|
-
|
2617
|
-
|
2618
|
-
args.concat(["MATCH", match])
|
2619
|
-
end
|
2620
|
-
|
2621
|
-
if count = options[:count]
|
2622
|
-
args.concat(["COUNT", count])
|
2623
|
-
end
|
2625
|
+
args << "MATCH" << match if match
|
2626
|
+
args << "COUNT" << count if count
|
2624
2627
|
|
2625
2628
|
synchronize do |client|
|
2626
2629
|
client.call([command] + args, &block)
|
@@ -2642,8 +2645,8 @@ class Redis
|
|
2642
2645
|
# - `:count => Integer`: return count keys at most per iteration
|
2643
2646
|
#
|
2644
2647
|
# @return [String, Array<String>] the next cursor and all found keys
|
2645
|
-
def scan(cursor, options
|
2646
|
-
_scan(:scan, cursor, [], options)
|
2648
|
+
def scan(cursor, **options)
|
2649
|
+
_scan(:scan, cursor, [], **options)
|
2647
2650
|
end
|
2648
2651
|
|
2649
2652
|
# Scan the keyspace
|
@@ -2661,11 +2664,12 @@ class Redis
|
|
2661
2664
|
# - `:count => Integer`: return count keys at most per iteration
|
2662
2665
|
#
|
2663
2666
|
# @return [Enumerator] an enumerator for all found keys
|
2664
|
-
def scan_each(options
|
2665
|
-
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
|
+
|
2666
2670
|
cursor = 0
|
2667
2671
|
loop do
|
2668
|
-
cursor, keys = scan(cursor, options)
|
2672
|
+
cursor, keys = scan(cursor, **options)
|
2669
2673
|
keys.each(&block)
|
2670
2674
|
break if cursor == "0"
|
2671
2675
|
end
|
@@ -2682,8 +2686,8 @@ class Redis
|
|
2682
2686
|
# - `:count => Integer`: return count keys at most per iteration
|
2683
2687
|
#
|
2684
2688
|
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
2685
|
-
def hscan(key, cursor, options
|
2686
|
-
_scan(:hscan, cursor, [key], options) do |reply|
|
2689
|
+
def hscan(key, cursor, **options)
|
2690
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2687
2691
|
[reply[0], reply[1].each_slice(2).to_a]
|
2688
2692
|
end
|
2689
2693
|
end
|
@@ -2699,11 +2703,12 @@ class Redis
|
|
2699
2703
|
# - `:count => Integer`: return count keys at most per iteration
|
2700
2704
|
#
|
2701
2705
|
# @return [Enumerator] an enumerator for all found keys
|
2702
|
-
def hscan_each(key, options
|
2703
|
-
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
|
+
|
2704
2709
|
cursor = 0
|
2705
2710
|
loop do
|
2706
|
-
cursor, values = hscan(key, cursor, options)
|
2711
|
+
cursor, values = hscan(key, cursor, **options)
|
2707
2712
|
values.each(&block)
|
2708
2713
|
break if cursor == "0"
|
2709
2714
|
end
|
@@ -2721,8 +2726,8 @@ class Redis
|
|
2721
2726
|
#
|
2722
2727
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2723
2728
|
# members and scores
|
2724
|
-
def zscan(key, cursor, options
|
2725
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2729
|
+
def zscan(key, cursor, **options)
|
2730
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2726
2731
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2727
2732
|
end
|
2728
2733
|
end
|
@@ -2738,11 +2743,12 @@ class Redis
|
|
2738
2743
|
# - `:count => Integer`: return count keys at most per iteration
|
2739
2744
|
#
|
2740
2745
|
# @return [Enumerator] an enumerator for all found scores and members
|
2741
|
-
def zscan_each(key, options
|
2742
|
-
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
|
+
|
2743
2749
|
cursor = 0
|
2744
2750
|
loop do
|
2745
|
-
cursor, values = zscan(key, cursor, options)
|
2751
|
+
cursor, values = zscan(key, cursor, **options)
|
2746
2752
|
values.each(&block)
|
2747
2753
|
break if cursor == "0"
|
2748
2754
|
end
|
@@ -2759,8 +2765,8 @@ class Redis
|
|
2759
2765
|
# - `:count => Integer`: return count keys at most per iteration
|
2760
2766
|
#
|
2761
2767
|
# @return [String, Array<String>] the next cursor and all found members
|
2762
|
-
def sscan(key, cursor, options
|
2763
|
-
_scan(:sscan, cursor, [key], options)
|
2768
|
+
def sscan(key, cursor, **options)
|
2769
|
+
_scan(:sscan, cursor, [key], **options)
|
2764
2770
|
end
|
2765
2771
|
|
2766
2772
|
# Scan a set
|
@@ -2774,11 +2780,12 @@ class Redis
|
|
2774
2780
|
# - `:count => Integer`: return count keys at most per iteration
|
2775
2781
|
#
|
2776
2782
|
# @return [Enumerator] an enumerator for all keys in the set
|
2777
|
-
def sscan_each(key, options
|
2778
|
-
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
|
+
|
2779
2786
|
cursor = 0
|
2780
2787
|
loop do
|
2781
|
-
cursor, keys = sscan(key, cursor, options)
|
2788
|
+
cursor, keys = sscan(key, cursor, **options)
|
2782
2789
|
keys.each(&block)
|
2783
2790
|
break if cursor == "0"
|
2784
2791
|
end
|
@@ -2842,12 +2849,12 @@ class Redis
|
|
2842
2849
|
end
|
2843
2850
|
end
|
2844
2851
|
|
2845
|
-
|
2846
2852
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2847
2853
|
# given maximum distance from a point
|
2848
2854
|
#
|
2849
2855
|
# @param [Array] args key, longitude, latitude, radius, unit(m|km|ft|mi)
|
2850
|
-
# @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
|
2851
2858
|
# @param [Integer] count limit the results to the first N matching items
|
2852
2859
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2853
2860
|
# @return [Array<String>] may be changed with `options`
|
@@ -2864,7 +2871,8 @@ class Redis
|
|
2864
2871
|
# given maximum distance from an already existing member
|
2865
2872
|
#
|
2866
2873
|
# @param [Array] args key, member, radius, unit(m|km|ft|mi)
|
2867
|
-
# @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
|
2868
2876
|
# @param [Integer] count limit the results to the first N matching items
|
2869
2877
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2870
2878
|
# @return [Array<String>] may be changed with `options`
|
@@ -2881,7 +2889,8 @@ class Redis
|
|
2881
2889
|
#
|
2882
2890
|
# @param [String] key
|
2883
2891
|
# @param [String, Array<String>] member one member or array of members
|
2884
|
-
# @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
|
2885
2894
|
def geopos(key, member)
|
2886
2895
|
synchronize do |client|
|
2887
2896
|
client.call([:geopos, key, member])
|
@@ -2945,10 +2954,14 @@ class Redis
|
|
2945
2954
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2946
2955
|
#
|
2947
2956
|
# @return [String] the entry id
|
2948
|
-
def xadd(key, entry,
|
2957
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2949
2958
|
args = [:xadd, key]
|
2950
|
-
|
2951
|
-
|
2959
|
+
if maxlen
|
2960
|
+
args << "MAXLEN"
|
2961
|
+
args << "~" if approximate
|
2962
|
+
args << maxlen
|
2963
|
+
end
|
2964
|
+
args << id
|
2952
2965
|
args.concat(entry.to_a.flatten)
|
2953
2966
|
synchronize { |client| client.call(args) }
|
2954
2967
|
end
|
@@ -3003,8 +3016,8 @@ class Redis
|
|
3003
3016
|
# @param count [Integer] the number of entries as limit
|
3004
3017
|
#
|
3005
3018
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3006
|
-
def xrange(key, start = '-',
|
3007
|
-
args = [:xrange, key, start,
|
3019
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3020
|
+
args = [:xrange, key, start, range_end]
|
3008
3021
|
args.concat(['COUNT', count]) if count
|
3009
3022
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3010
3023
|
end
|
@@ -3026,8 +3039,8 @@ class Redis
|
|
3026
3039
|
# @params count [Integer] the number of entries as limit
|
3027
3040
|
#
|
3028
3041
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3029
|
-
def xrevrange(key,
|
3030
|
-
args = [:xrevrange, key,
|
3042
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3043
|
+
args = [:xrevrange, key, range_end, start]
|
3031
3044
|
args.concat(['COUNT', count]) if count
|
3032
3045
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3033
3046
|
end
|
@@ -3119,12 +3132,12 @@ class Redis
|
|
3119
3132
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3120
3133
|
#
|
3121
3134
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3122
|
-
def xreadgroup(group, consumer, keys, ids,
|
3135
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3123
3136
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3124
|
-
args << 'COUNT' <<
|
3125
|
-
args << 'BLOCK' <<
|
3126
|
-
args << 'NOACK' if
|
3127
|
-
_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)
|
3128
3141
|
end
|
3129
3142
|
|
3130
3143
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3234,8 +3247,8 @@ class Redis
|
|
3234
3247
|
when "get-master-addr-by-name"
|
3235
3248
|
reply
|
3236
3249
|
else
|
3237
|
-
if reply.
|
3238
|
-
if reply[0].
|
3250
|
+
if reply.is_a?(Array)
|
3251
|
+
if reply[0].is_a?(Array)
|
3239
3252
|
reply.map(&Hashify)
|
3240
3253
|
else
|
3241
3254
|
Hashify.call(reply)
|
@@ -3259,12 +3272,17 @@ class Redis
|
|
3259
3272
|
def cluster(subcommand, *args)
|
3260
3273
|
subcommand = subcommand.to_s.downcase
|
3261
3274
|
block = case subcommand
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
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
|
3268
3286
|
|
3269
3287
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3270
3288
|
block = Noop unless @cluster_mode
|
@@ -3299,21 +3317,21 @@ class Redis
|
|
3299
3317
|
return @original_client.connection_info if @cluster_mode
|
3300
3318
|
|
3301
3319
|
{
|
3302
|
-
host:
|
3303
|
-
port:
|
3304
|
-
db:
|
3305
|
-
id:
|
3320
|
+
host: @original_client.host,
|
3321
|
+
port: @original_client.port,
|
3322
|
+
db: @original_client.db,
|
3323
|
+
id: @original_client.id,
|
3306
3324
|
location: @original_client.location
|
3307
3325
|
}
|
3308
3326
|
end
|
3309
3327
|
|
3310
|
-
def method_missing(command, *args)
|
3328
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3311
3329
|
synchronize do |client|
|
3312
3330
|
client.call([command] + args)
|
3313
3331
|
end
|
3314
3332
|
end
|
3315
3333
|
|
3316
|
-
private
|
3334
|
+
private
|
3317
3335
|
|
3318
3336
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3319
3337
|
# where the method call will return nil. Propagate the nil instead of falsely
|
@@ -3393,10 +3411,10 @@ private
|
|
3393
3411
|
|
3394
3412
|
HashifyStreamPendings = lambda { |reply|
|
3395
3413
|
{
|
3396
|
-
'size'
|
3414
|
+
'size' => reply[0],
|
3397
3415
|
'min_entry_id' => reply[1],
|
3398
3416
|
'max_entry_id' => reply[2],
|
3399
|
-
'consumers'
|
3417
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3400
3418
|
}
|
3401
3419
|
}
|
3402
3420
|
|
@@ -3405,8 +3423,8 @@ private
|
|
3405
3423
|
{
|
3406
3424
|
'entry_id' => arr[0],
|
3407
3425
|
'consumer' => arr[1],
|
3408
|
-
'elapsed'
|
3409
|
-
'count'
|
3426
|
+
'elapsed' => arr[2],
|
3427
|
+
'count' => arr[3]
|
3410
3428
|
}
|
3411
3429
|
end
|
3412
3430
|
}
|
@@ -3414,15 +3432,15 @@ private
|
|
3414
3432
|
HashifyClusterNodeInfo = lambda { |str|
|
3415
3433
|
arr = str.split(' ')
|
3416
3434
|
{
|
3417
|
-
'node_id'
|
3418
|
-
'ip_port'
|
3419
|
-
'flags'
|
3435
|
+
'node_id' => arr[0],
|
3436
|
+
'ip_port' => arr[1],
|
3437
|
+
'flags' => arr[2].split(','),
|
3420
3438
|
'master_node_id' => arr[3],
|
3421
|
-
'ping_sent'
|
3422
|
-
'pong_recv'
|
3423
|
-
'config_epoch'
|
3424
|
-
'link_state'
|
3425
|
-
'slots'
|
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('-'))
|
3426
3444
|
}
|
3427
3445
|
}
|
3428
3446
|
|
@@ -3433,9 +3451,9 @@ private
|
|
3433
3451
|
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3434
3452
|
{
|
3435
3453
|
'start_slot' => first_slot,
|
3436
|
-
'end_slot'
|
3437
|
-
'master'
|
3438
|
-
'replicas'
|
3454
|
+
'end_slot' => last_slot,
|
3455
|
+
'master' => master,
|
3456
|
+
'replicas' => replicas
|
3439
3457
|
}
|
3440
3458
|
end
|
3441
3459
|
}
|