redis 4.1.4 → 4.2.4
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 +35 -0
- data/README.md +9 -4
- data/lib/redis.rb +287 -248
- data/lib/redis/client.rb +71 -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 +88 -94
- data/lib/redis/connection/synchrony.rb +8 -4
- data/lib/redis/distributed.rb +108 -57
- 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 +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7c23f28cc1a4b66b70d9caf4b890ce521145a51435921e65d5676ce7145c2bf
|
4
|
+
data.tar.gz: b88ecef94de49b0419ed1e1152fc05b5a6999a53883235b09b2eef0df3d37d9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4904a1b642fe757601a0c3bb34cb1d1160ca6bdf269624ae73a9d73599c11ad2d8e52a93ba1396bd76c71f31456211d7332d3c8fa16dd44d2ceb92826cbe86cc
|
7
|
+
data.tar.gz: d491bf50bca0c804d1b594ebf2de1d5b5a1d464873fe0d03986464006638028e7dd2b2056ed24919bb70a8c60c9a9fabf0e73663e8065bd474baf52abbf95d98
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.2.4
|
4
|
+
|
5
|
+
* Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
|
6
|
+
|
7
|
+
# 4.2.3
|
8
|
+
|
9
|
+
* Use io/wait instead of IO.select in the ruby connector. See #960.
|
10
|
+
* Use exception free non blocking IOs in the ruby connector. See #926.
|
11
|
+
* Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
|
12
|
+
|
13
|
+
# 4.2.2
|
14
|
+
|
15
|
+
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
16
|
+
* Fix handling of empty stream responses. See #905, #929.
|
17
|
+
|
18
|
+
# 4.2.1
|
19
|
+
|
20
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
21
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
22
|
+
|
23
|
+
# 4.2.0
|
24
|
+
|
25
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
26
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
27
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
28
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
29
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
30
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
31
|
+
* Support `keepttl` ooption in `set`. See #913.
|
32
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
33
|
+
* Accept sentinel options even with string key. See #599.
|
34
|
+
* Verify TLS connections by default. See #900.
|
35
|
+
* Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
|
36
|
+
|
3
37
|
# 4.1.4
|
4
38
|
|
5
39
|
* Alias `Redis#disconnect` as `#close`. See #901.
|
@@ -9,6 +43,7 @@
|
|
9
43
|
* Increase buffer size in the ruby connector. See #880.
|
10
44
|
* Fix thread safety of `Redis.queue`. See #878.
|
11
45
|
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
46
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
12
47
|
|
13
48
|
# 4.1.3
|
14
49
|
|
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"
|
@@ -261,6 +265,7 @@ All timeout values are specified in seconds.
|
|
261
265
|
When using pub/sub, you can subscribe to a channel using a timeout as well:
|
262
266
|
|
263
267
|
```ruby
|
268
|
+
redis = Redis.new(reconnect_attempts: 0)
|
264
269
|
redis.subscribe_with_timeout(5, "news") do |on|
|
265
270
|
on.message do |channel, message|
|
266
271
|
# ...
|
@@ -322,7 +327,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
322
327
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
323
328
|
or [ghostunnel].
|
324
329
|
|
325
|
-
To enable SSL support, pass the `:ssl =>
|
330
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
326
331
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
327
332
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
328
333
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -451,7 +456,7 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
451
456
|
## Contributing
|
452
457
|
|
453
458
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
454
|
-
requests.
|
459
|
+
requests.
|
455
460
|
|
456
461
|
|
457
462
|
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
data/lib/redis.rb
CHANGED
@@ -4,12 +4,26 @@ require "monitor"
|
|
4
4
|
require_relative "redis/errors"
|
5
5
|
|
6
6
|
class Redis
|
7
|
-
|
8
|
-
|
7
|
+
class << self
|
8
|
+
attr_reader :exists_returns_integer
|
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
|
9
23
|
end
|
10
24
|
|
11
|
-
def self.current
|
12
|
-
@current
|
25
|
+
def self.current
|
26
|
+
@current ||= Redis.new
|
13
27
|
end
|
14
28
|
|
15
29
|
include MonitorMixin
|
@@ -17,7 +31,9 @@ class Redis
|
|
17
31
|
# Create a new client instance
|
18
32
|
#
|
19
33
|
# @param [Hash] options
|
20
|
-
# @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.
|
21
37
|
# @option options [String] :host ("127.0.0.1") server hostname
|
22
38
|
# @option options [Integer] :port (6379) server port
|
23
39
|
# @option options [String] :path path to server socket (overrides host and port)
|
@@ -26,8 +42,10 @@ class Redis
|
|
26
42
|
# @option options [String] :password Password to authenticate against server
|
27
43
|
# @option options [Integer] :db (0) Database to select after initial connect
|
28
44
|
# @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
|
-
#
|
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
|
31
49
|
# @option options [Integer] :reconnect_attempts Number of attempts trying to connect
|
32
50
|
# @option options [Boolean] :inherit_socket (false) Whether to use socket in forked process or not
|
33
51
|
# @option options [Array] :sentinels List of sentinels to contact
|
@@ -52,7 +70,7 @@ class Redis
|
|
52
70
|
end
|
53
71
|
|
54
72
|
# Run code with the client reconnecting
|
55
|
-
def with_reconnect(val=true, &blk)
|
73
|
+
def with_reconnect(val = true, &blk)
|
56
74
|
synchronize do |client|
|
57
75
|
client.with_reconnect(val, &blk)
|
58
76
|
end
|
@@ -205,7 +223,7 @@ class Redis
|
|
205
223
|
def config(action, *args)
|
206
224
|
synchronize do |client|
|
207
225
|
client.call([:config, action] + args) do |reply|
|
208
|
-
if reply.
|
226
|
+
if reply.is_a?(Array) && action == :get
|
209
227
|
Hashify.call(reply)
|
210
228
|
else
|
211
229
|
reply
|
@@ -256,7 +274,7 @@ class Redis
|
|
256
274
|
def flushall(options = nil)
|
257
275
|
synchronize do |client|
|
258
276
|
if options && options[:async]
|
259
|
-
client.call([
|
277
|
+
client.call(%i[flushall async])
|
260
278
|
else
|
261
279
|
client.call([:flushall])
|
262
280
|
end
|
@@ -271,7 +289,7 @@ class Redis
|
|
271
289
|
def flushdb(options = nil)
|
272
290
|
synchronize do |client|
|
273
291
|
if options && options[:async]
|
274
|
-
client.call([
|
292
|
+
client.call(%i[flushdb async])
|
275
293
|
else
|
276
294
|
client.call([:flushdb])
|
277
295
|
end
|
@@ -285,7 +303,7 @@ class Redis
|
|
285
303
|
def info(cmd = nil)
|
286
304
|
synchronize do |client|
|
287
305
|
client.call([:info, cmd].compact) do |reply|
|
288
|
-
if reply.
|
306
|
+
if reply.is_a?(String)
|
289
307
|
reply = HashifyInfo.call(reply)
|
290
308
|
|
291
309
|
if cmd && cmd.to_s == "commandstats"
|
@@ -358,7 +376,7 @@ class Redis
|
|
358
376
|
# @param [String] subcommand e.g. `get`, `len`, `reset`
|
359
377
|
# @param [Integer] length maximum number of entries to return
|
360
378
|
# @return [Array<String>, Integer, String] depends on subcommand
|
361
|
-
def slowlog(subcommand, length=nil)
|
379
|
+
def slowlog(subcommand, length = nil)
|
362
380
|
synchronize do |client|
|
363
381
|
args = [:slowlog, subcommand]
|
364
382
|
args << length if length
|
@@ -383,7 +401,7 @@ class Redis
|
|
383
401
|
def time
|
384
402
|
synchronize do |client|
|
385
403
|
client.call([:time]) do |reply|
|
386
|
-
reply
|
404
|
+
reply&.map(&:to_i)
|
387
405
|
end
|
388
406
|
end
|
389
407
|
end
|
@@ -496,9 +514,9 @@ class Redis
|
|
496
514
|
# - `:replace => Boolean`: if false, raises an error if key already exists
|
497
515
|
# @raise [Redis::CommandError]
|
498
516
|
# @return [String] `"OK"`
|
499
|
-
def restore(key, ttl, serialized_value,
|
517
|
+
def restore(key, ttl, serialized_value, replace: nil)
|
500
518
|
args = [:restore, key, ttl, serialized_value]
|
501
|
-
args << 'REPLACE' if
|
519
|
+
args << 'REPLACE' if replace
|
502
520
|
|
503
521
|
synchronize do |client|
|
504
522
|
client.call(args)
|
@@ -550,13 +568,43 @@ class Redis
|
|
550
568
|
end
|
551
569
|
end
|
552
570
|
|
553
|
-
# Determine
|
571
|
+
# Determine how many of the keys exists.
|
554
572
|
#
|
555
|
-
# @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
|
556
602
|
# @return [Boolean]
|
557
|
-
def exists(
|
603
|
+
def exists?(*keys)
|
558
604
|
synchronize do |client|
|
559
|
-
client.call([:exists,
|
605
|
+
client.call([:exists, *keys]) do |value|
|
606
|
+
value > 0
|
607
|
+
end
|
560
608
|
end
|
561
609
|
end
|
562
610
|
|
@@ -567,7 +615,7 @@ class Redis
|
|
567
615
|
def keys(pattern = "*")
|
568
616
|
synchronize do |client|
|
569
617
|
client.call([:keys, pattern]) do |reply|
|
570
|
-
if reply.
|
618
|
+
if reply.is_a?(String)
|
571
619
|
reply.split(" ")
|
572
620
|
else
|
573
621
|
reply
|
@@ -663,30 +711,27 @@ class Redis
|
|
663
711
|
# elements where every element is an array with the result for every
|
664
712
|
# element specified in `:get`
|
665
713
|
# - when `:store` is specified, the number of elements in the stored result
|
666
|
-
def sort(key,
|
667
|
-
args = []
|
714
|
+
def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
|
715
|
+
args = [:sort, key]
|
716
|
+
args << "BY" << by if by
|
668
717
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
args.concat(["LIMIT"] + limit) if limit
|
718
|
+
if limit
|
719
|
+
args << "LIMIT"
|
720
|
+
args.concat(limit)
|
721
|
+
end
|
674
722
|
|
675
|
-
get = Array(
|
676
|
-
|
723
|
+
get = Array(get)
|
724
|
+
get.each do |item|
|
725
|
+
args << "GET" << item
|
726
|
+
end
|
677
727
|
|
678
|
-
order = options[:order]
|
679
728
|
args.concat(order.split(" ")) if order
|
680
|
-
|
681
|
-
store = options[:store]
|
682
|
-
args.concat(["STORE", store]) if store
|
729
|
+
args << "STORE" << store if store
|
683
730
|
|
684
731
|
synchronize do |client|
|
685
|
-
client.call(
|
732
|
+
client.call(args) do |reply|
|
686
733
|
if get.size > 1 && !store
|
687
|
-
if reply
|
688
|
-
reply.each_slice(get.size).to_a
|
689
|
-
end
|
734
|
+
reply.each_slice(get.size).to_a if reply
|
690
735
|
else
|
691
736
|
reply
|
692
737
|
end
|
@@ -786,27 +831,21 @@ class Redis
|
|
786
831
|
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
787
832
|
# - `:nx => true`: Only set the key if it does not already exist.
|
788
833
|
# - `:xx => true`: Only set the key if it already exist.
|
834
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
789
835
|
# @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
|
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
|
804
843
|
|
805
844
|
synchronize do |client|
|
806
845
|
if nx || xx
|
807
|
-
client.call(
|
846
|
+
client.call(args, &BoolifySet)
|
808
847
|
else
|
809
|
-
client.call(
|
848
|
+
client.call(args)
|
810
849
|
end
|
811
850
|
end
|
812
851
|
end
|
@@ -888,7 +927,7 @@ class Redis
|
|
888
927
|
# @see #mapped_msetnx
|
889
928
|
def msetnx(*args)
|
890
929
|
synchronize do |client|
|
891
|
-
client.call([:msetnx
|
930
|
+
client.call([:msetnx, *args], &Boolify)
|
892
931
|
end
|
893
932
|
end
|
894
933
|
|
@@ -928,7 +967,7 @@ class Redis
|
|
928
967
|
# @see #mapped_mget
|
929
968
|
def mget(*keys, &blk)
|
930
969
|
synchronize do |client|
|
931
|
-
client.call([:mget
|
970
|
+
client.call([:mget, *keys], &blk)
|
932
971
|
end
|
933
972
|
end
|
934
973
|
|
@@ -944,7 +983,7 @@ class Redis
|
|
944
983
|
# @see #mget
|
945
984
|
def mapped_mget(*keys)
|
946
985
|
mget(*keys) do |reply|
|
947
|
-
if reply.
|
986
|
+
if reply.is_a?(Array)
|
948
987
|
Hash[keys.zip(reply)]
|
949
988
|
else
|
950
989
|
reply
|
@@ -1031,7 +1070,7 @@ class Redis
|
|
1031
1070
|
# @return [Integer] the length of the string stored in `destkey`
|
1032
1071
|
def bitop(operation, destkey, *keys)
|
1033
1072
|
synchronize do |client|
|
1034
|
-
client.call([:bitop, operation, destkey
|
1073
|
+
client.call([:bitop, operation, destkey, *keys])
|
1035
1074
|
end
|
1036
1075
|
end
|
1037
1076
|
|
@@ -1043,10 +1082,8 @@ class Redis
|
|
1043
1082
|
# @param [Integer] stop stop index
|
1044
1083
|
# @return [Integer] the position of the first 1/0 bit.
|
1045
1084
|
# -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
|
1085
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
1086
|
+
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
1050
1087
|
|
1051
1088
|
synchronize do |client|
|
1052
1089
|
command = [:bitpos, key, bit]
|
@@ -1240,15 +1277,7 @@ class Redis
|
|
1240
1277
|
# @return [nil, String]
|
1241
1278
|
# - `nil` when the operation timed out
|
1242
1279
|
# - 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
|
-
|
1280
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, timeout: deprecated_timeout)
|
1252
1281
|
synchronize do |client|
|
1253
1282
|
command = [:brpoplpush, source, destination, timeout]
|
1254
1283
|
timeout += client.timeout if timeout > 0
|
@@ -1455,7 +1484,7 @@ class Redis
|
|
1455
1484
|
# @return [Array<String>] members in the difference
|
1456
1485
|
def sdiff(*keys)
|
1457
1486
|
synchronize do |client|
|
1458
|
-
client.call([:sdiff
|
1487
|
+
client.call([:sdiff, *keys])
|
1459
1488
|
end
|
1460
1489
|
end
|
1461
1490
|
|
@@ -1466,7 +1495,7 @@ class Redis
|
|
1466
1495
|
# @return [Integer] number of elements in the resulting set
|
1467
1496
|
def sdiffstore(destination, *keys)
|
1468
1497
|
synchronize do |client|
|
1469
|
-
client.call([:sdiffstore, destination
|
1498
|
+
client.call([:sdiffstore, destination, *keys])
|
1470
1499
|
end
|
1471
1500
|
end
|
1472
1501
|
|
@@ -1476,7 +1505,7 @@ class Redis
|
|
1476
1505
|
# @return [Array<String>] members in the intersection
|
1477
1506
|
def sinter(*keys)
|
1478
1507
|
synchronize do |client|
|
1479
|
-
client.call([:sinter
|
1508
|
+
client.call([:sinter, *keys])
|
1480
1509
|
end
|
1481
1510
|
end
|
1482
1511
|
|
@@ -1487,7 +1516,7 @@ class Redis
|
|
1487
1516
|
# @return [Integer] number of elements in the resulting set
|
1488
1517
|
def sinterstore(destination, *keys)
|
1489
1518
|
synchronize do |client|
|
1490
|
-
client.call([:sinterstore, destination
|
1519
|
+
client.call([:sinterstore, destination, *keys])
|
1491
1520
|
end
|
1492
1521
|
end
|
1493
1522
|
|
@@ -1497,7 +1526,7 @@ class Redis
|
|
1497
1526
|
# @return [Array<String>] members in the union
|
1498
1527
|
def sunion(*keys)
|
1499
1528
|
synchronize do |client|
|
1500
|
-
client.call([:sunion
|
1529
|
+
client.call([:sunion, *keys])
|
1501
1530
|
end
|
1502
1531
|
end
|
1503
1532
|
|
@@ -1508,7 +1537,7 @@ class Redis
|
|
1508
1537
|
# @return [Integer] number of elements in the resulting set
|
1509
1538
|
def sunionstore(destination, *keys)
|
1510
1539
|
synchronize do |client|
|
1511
|
-
client.call([:sunionstore, destination
|
1540
|
+
client.call([:sunionstore, destination, *keys])
|
1512
1541
|
end
|
1513
1542
|
end
|
1514
1543
|
|
@@ -1557,31 +1586,20 @@ class Redis
|
|
1557
1586
|
# pairs that were **added** to the sorted set.
|
1558
1587
|
# - `Float` when option :incr is specified, holding the score of the member
|
1559
1588
|
# 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
|
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
|
1577
1595
|
|
1578
1596
|
synchronize do |client|
|
1579
1597
|
if args.size == 1 && args[0].is_a?(Array)
|
1580
1598
|
# Variadic: return float if INCR, integer if !INCR
|
1581
|
-
client.call(
|
1599
|
+
client.call(command + args[0], &(incr ? Floatify : nil))
|
1582
1600
|
elsif args.size == 2
|
1583
1601
|
# Single pair: return float if INCR, boolean if !INCR
|
1584
|
-
client.call(
|
1602
|
+
client.call(command + args, &(incr ? Floatify : Boolify))
|
1585
1603
|
else
|
1586
1604
|
raise ArgumentError, "wrong number of arguments"
|
1587
1605
|
end
|
@@ -1752,10 +1770,8 @@ class Redis
|
|
1752
1770
|
# @return [Array<String>, Array<[String, Float]>]
|
1753
1771
|
# - when `:with_scores` is not specified, an array of members
|
1754
1772
|
# - 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]
|
1773
|
+
def zrange(key, start, stop, withscores: false, with_scores: withscores)
|
1774
|
+
args = [:zrange, key, start, stop]
|
1759
1775
|
|
1760
1776
|
if with_scores
|
1761
1777
|
args << "WITHSCORES"
|
@@ -1763,7 +1779,7 @@ class Redis
|
|
1763
1779
|
end
|
1764
1780
|
|
1765
1781
|
synchronize do |client|
|
1766
|
-
client.call(
|
1782
|
+
client.call(args, &block)
|
1767
1783
|
end
|
1768
1784
|
end
|
1769
1785
|
|
@@ -1778,10 +1794,8 @@ class Redis
|
|
1778
1794
|
# # => [["b", 64.0], ["a", 32.0]]
|
1779
1795
|
#
|
1780
1796
|
# @see #zrange
|
1781
|
-
def zrevrange(key, start, stop,
|
1782
|
-
args = []
|
1783
|
-
|
1784
|
-
with_scores = options[:with_scores] || options[:withscores]
|
1797
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
1798
|
+
args = [:zrevrange, key, start, stop]
|
1785
1799
|
|
1786
1800
|
if with_scores
|
1787
1801
|
args << "WITHSCORES"
|
@@ -1789,7 +1803,7 @@ class Redis
|
|
1789
1803
|
end
|
1790
1804
|
|
1791
1805
|
synchronize do |client|
|
1792
|
-
client.call(
|
1806
|
+
client.call(args, &block)
|
1793
1807
|
end
|
1794
1808
|
end
|
1795
1809
|
|
@@ -1880,14 +1894,16 @@ class Redis
|
|
1880
1894
|
# `count` members
|
1881
1895
|
#
|
1882
1896
|
# @return [Array<String>, Array<[String, Float]>]
|
1883
|
-
def zrangebylex(key, min, max,
|
1884
|
-
args = []
|
1897
|
+
def zrangebylex(key, min, max, limit: nil)
|
1898
|
+
args = [:zrangebylex, key, min, max]
|
1885
1899
|
|
1886
|
-
|
1887
|
-
|
1900
|
+
if limit
|
1901
|
+
args << "LIMIT"
|
1902
|
+
args.concat(limit)
|
1903
|
+
end
|
1888
1904
|
|
1889
1905
|
synchronize do |client|
|
1890
|
-
client.call(
|
1906
|
+
client.call(args)
|
1891
1907
|
end
|
1892
1908
|
end
|
1893
1909
|
|
@@ -1902,14 +1918,16 @@ class Redis
|
|
1902
1918
|
# # => ["abbygail", "abby"]
|
1903
1919
|
#
|
1904
1920
|
# @see #zrangebylex
|
1905
|
-
def zrevrangebylex(key, max, min,
|
1906
|
-
args = []
|
1921
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
1922
|
+
args = [:zrevrangebylex, key, max, min]
|
1907
1923
|
|
1908
|
-
|
1909
|
-
|
1924
|
+
if limit
|
1925
|
+
args << "LIMIT"
|
1926
|
+
args.concat(limit)
|
1927
|
+
end
|
1910
1928
|
|
1911
1929
|
synchronize do |client|
|
1912
|
-
client.call(
|
1930
|
+
client.call(args)
|
1913
1931
|
end
|
1914
1932
|
end
|
1915
1933
|
|
@@ -1940,21 +1958,21 @@ class Redis
|
|
1940
1958
|
# @return [Array<String>, Array<[String, Float]>]
|
1941
1959
|
# - when `:with_scores` is not specified, an array of members
|
1942
1960
|
# - 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]
|
1961
|
+
def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
|
1962
|
+
args = [:zrangebyscore, key, min, max]
|
1947
1963
|
|
1948
1964
|
if with_scores
|
1949
1965
|
args << "WITHSCORES"
|
1950
1966
|
block = FloatifyPairs
|
1951
1967
|
end
|
1952
1968
|
|
1953
|
-
|
1954
|
-
|
1969
|
+
if limit
|
1970
|
+
args << "LIMIT"
|
1971
|
+
args.concat(limit)
|
1972
|
+
end
|
1955
1973
|
|
1956
1974
|
synchronize do |client|
|
1957
|
-
client.call(
|
1975
|
+
client.call(args, &block)
|
1958
1976
|
end
|
1959
1977
|
end
|
1960
1978
|
|
@@ -1972,21 +1990,21 @@ class Redis
|
|
1972
1990
|
# # => [["b", 64.0], ["a", 32.0]]
|
1973
1991
|
#
|
1974
1992
|
# @see #zrangebyscore
|
1975
|
-
def zrevrangebyscore(key, max, min,
|
1976
|
-
args = []
|
1977
|
-
|
1978
|
-
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]
|
1979
1995
|
|
1980
1996
|
if with_scores
|
1981
|
-
args <<
|
1997
|
+
args << "WITHSCORES"
|
1982
1998
|
block = FloatifyPairs
|
1983
1999
|
end
|
1984
2000
|
|
1985
|
-
|
1986
|
-
|
2001
|
+
if limit
|
2002
|
+
args << "LIMIT"
|
2003
|
+
args.concat(limit)
|
2004
|
+
end
|
1987
2005
|
|
1988
2006
|
synchronize do |client|
|
1989
|
-
client.call(
|
2007
|
+
client.call(args, &block)
|
1990
2008
|
end
|
1991
2009
|
end
|
1992
2010
|
|
@@ -2050,17 +2068,18 @@ class Redis
|
|
2050
2068
|
# sorted sets
|
2051
2069
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2052
2070
|
# @return [Integer] number of elements in the resulting sorted set
|
2053
|
-
def zinterstore(destination, keys,
|
2054
|
-
args = []
|
2071
|
+
def zinterstore(destination, keys, weights: nil, aggregate: nil)
|
2072
|
+
args = [:zinterstore, destination, keys.size, *keys]
|
2055
2073
|
|
2056
|
-
|
2057
|
-
|
2074
|
+
if weights
|
2075
|
+
args << "WEIGHTS"
|
2076
|
+
args.concat(weights)
|
2077
|
+
end
|
2058
2078
|
|
2059
|
-
aggregate
|
2060
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2079
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2061
2080
|
|
2062
2081
|
synchronize do |client|
|
2063
|
-
client.call(
|
2082
|
+
client.call(args)
|
2064
2083
|
end
|
2065
2084
|
end
|
2066
2085
|
|
@@ -2077,17 +2096,18 @@ class Redis
|
|
2077
2096
|
# sorted sets
|
2078
2097
|
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2079
2098
|
# @return [Integer] number of elements in the resulting sorted set
|
2080
|
-
def zunionstore(destination, keys,
|
2081
|
-
args = []
|
2099
|
+
def zunionstore(destination, keys, weights: nil, aggregate: nil)
|
2100
|
+
args = [:zunionstore, destination, keys.size, *keys]
|
2082
2101
|
|
2083
|
-
|
2084
|
-
|
2102
|
+
if weights
|
2103
|
+
args << "WEIGHTS"
|
2104
|
+
args.concat(weights)
|
2105
|
+
end
|
2085
2106
|
|
2086
|
-
aggregate
|
2087
|
-
args.concat(["AGGREGATE", aggregate]) if aggregate
|
2107
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2088
2108
|
|
2089
2109
|
synchronize do |client|
|
2090
|
-
client.call(
|
2110
|
+
client.call(args)
|
2091
2111
|
end
|
2092
2112
|
end
|
2093
2113
|
|
@@ -2101,15 +2121,20 @@ class Redis
|
|
2101
2121
|
end
|
2102
2122
|
end
|
2103
2123
|
|
2104
|
-
# 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
|
2105
2129
|
#
|
2106
2130
|
# @param [String] key
|
2107
|
-
# @param [String]
|
2108
|
-
# @
|
2109
|
-
|
2110
|
-
|
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
|
+
|
2111
2136
|
synchronize do |client|
|
2112
|
-
client.call([:hset, key,
|
2137
|
+
client.call([:hset, key, *attrs])
|
2113
2138
|
end
|
2114
2139
|
end
|
2115
2140
|
|
@@ -2198,7 +2223,7 @@ class Redis
|
|
2198
2223
|
# @see #hmget
|
2199
2224
|
def mapped_hmget(key, *fields)
|
2200
2225
|
hmget(key, *fields) do |reply|
|
2201
|
-
if reply.
|
2226
|
+
if reply.is_a?(Array)
|
2202
2227
|
Hash[fields.zip(reply)]
|
2203
2228
|
else
|
2204
2229
|
reply
|
@@ -2291,20 +2316,21 @@ class Redis
|
|
2291
2316
|
|
2292
2317
|
def subscribed?
|
2293
2318
|
synchronize do |client|
|
2294
|
-
client.
|
2319
|
+
client.is_a? SubscribedClient
|
2295
2320
|
end
|
2296
2321
|
end
|
2297
2322
|
|
2298
2323
|
# Listen for messages published to the given channels.
|
2299
2324
|
def subscribe(*channels, &block)
|
2300
|
-
synchronize do |
|
2325
|
+
synchronize do |_client|
|
2301
2326
|
_subscription(:subscribe, 0, channels, block)
|
2302
2327
|
end
|
2303
2328
|
end
|
2304
2329
|
|
2305
|
-
# 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.
|
2306
2332
|
def subscribe_with_timeout(timeout, *channels, &block)
|
2307
|
-
synchronize do |
|
2333
|
+
synchronize do |_client|
|
2308
2334
|
_subscription(:subscribe_with_timeout, timeout, channels, block)
|
2309
2335
|
end
|
2310
2336
|
end
|
@@ -2312,21 +2338,23 @@ class Redis
|
|
2312
2338
|
# Stop listening for messages posted to the given channels.
|
2313
2339
|
def unsubscribe(*channels)
|
2314
2340
|
synchronize do |client|
|
2315
|
-
raise
|
2341
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2342
|
+
|
2316
2343
|
client.unsubscribe(*channels)
|
2317
2344
|
end
|
2318
2345
|
end
|
2319
2346
|
|
2320
2347
|
# Listen for messages published to channels matching the given patterns.
|
2321
2348
|
def psubscribe(*channels, &block)
|
2322
|
-
synchronize do |
|
2349
|
+
synchronize do |_client|
|
2323
2350
|
_subscription(:psubscribe, 0, channels, block)
|
2324
2351
|
end
|
2325
2352
|
end
|
2326
2353
|
|
2327
|
-
# 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.
|
2328
2356
|
def psubscribe_with_timeout(timeout, *channels, &block)
|
2329
|
-
synchronize do |
|
2357
|
+
synchronize do |_client|
|
2330
2358
|
_subscription(:psubscribe_with_timeout, timeout, channels, block)
|
2331
2359
|
end
|
2332
2360
|
end
|
@@ -2334,7 +2362,8 @@ class Redis
|
|
2334
2362
|
# Stop listening for messages posted to channels matching the given patterns.
|
2335
2363
|
def punsubscribe(*channels)
|
2336
2364
|
synchronize do |client|
|
2337
|
-
raise
|
2365
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
2366
|
+
|
2338
2367
|
client.punsubscribe(*channels)
|
2339
2368
|
end
|
2340
2369
|
end
|
@@ -2379,7 +2408,7 @@ class Redis
|
|
2379
2408
|
# @see #multi
|
2380
2409
|
def watch(*keys)
|
2381
2410
|
synchronize do |client|
|
2382
|
-
res = client.call([:watch
|
2411
|
+
res = client.call([:watch, *keys])
|
2383
2412
|
|
2384
2413
|
if block_given?
|
2385
2414
|
begin
|
@@ -2409,14 +2438,13 @@ class Redis
|
|
2409
2438
|
end
|
2410
2439
|
|
2411
2440
|
def pipelined
|
2412
|
-
synchronize do |
|
2441
|
+
synchronize do |prior_client|
|
2413
2442
|
begin
|
2414
|
-
|
2415
|
-
original, @client = @client, pipeline
|
2443
|
+
@client = Pipeline.new(prior_client)
|
2416
2444
|
yield(self)
|
2417
|
-
|
2445
|
+
prior_client.call_pipeline(@client)
|
2418
2446
|
ensure
|
2419
|
-
@client =
|
2447
|
+
@client = prior_client
|
2420
2448
|
end
|
2421
2449
|
end
|
2422
2450
|
end
|
@@ -2452,17 +2480,16 @@ class Redis
|
|
2452
2480
|
# @see #watch
|
2453
2481
|
# @see #unwatch
|
2454
2482
|
def multi
|
2455
|
-
synchronize do |
|
2483
|
+
synchronize do |prior_client|
|
2456
2484
|
if !block_given?
|
2457
|
-
|
2485
|
+
prior_client.call([:multi])
|
2458
2486
|
else
|
2459
2487
|
begin
|
2460
|
-
|
2461
|
-
original, @client = @client, pipeline
|
2488
|
+
@client = Pipeline::Multi.new(prior_client)
|
2462
2489
|
yield(self)
|
2463
|
-
|
2490
|
+
prior_client.call_pipeline(@client)
|
2464
2491
|
ensure
|
2465
|
-
@client =
|
2492
|
+
@client = prior_client
|
2466
2493
|
end
|
2467
2494
|
end
|
2468
2495
|
end
|
@@ -2609,18 +2636,12 @@ class Redis
|
|
2609
2636
|
_eval(:evalsha, args)
|
2610
2637
|
end
|
2611
2638
|
|
2612
|
-
def _scan(command, cursor, args,
|
2639
|
+
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2613
2640
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2614
2641
|
|
2615
2642
|
args << cursor
|
2616
|
-
|
2617
|
-
|
2618
|
-
args.concat(["MATCH", match])
|
2619
|
-
end
|
2620
|
-
|
2621
|
-
if count = options[:count]
|
2622
|
-
args.concat(["COUNT", count])
|
2623
|
-
end
|
2643
|
+
args << "MATCH" << match if match
|
2644
|
+
args << "COUNT" << count if count
|
2624
2645
|
|
2625
2646
|
synchronize do |client|
|
2626
2647
|
client.call([command] + args, &block)
|
@@ -2642,8 +2663,8 @@ class Redis
|
|
2642
2663
|
# - `:count => Integer`: return count keys at most per iteration
|
2643
2664
|
#
|
2644
2665
|
# @return [String, Array<String>] the next cursor and all found keys
|
2645
|
-
def scan(cursor, options
|
2646
|
-
_scan(:scan, cursor, [], options)
|
2666
|
+
def scan(cursor, **options)
|
2667
|
+
_scan(:scan, cursor, [], **options)
|
2647
2668
|
end
|
2648
2669
|
|
2649
2670
|
# Scan the keyspace
|
@@ -2661,11 +2682,12 @@ class Redis
|
|
2661
2682
|
# - `:count => Integer`: return count keys at most per iteration
|
2662
2683
|
#
|
2663
2684
|
# @return [Enumerator] an enumerator for all found keys
|
2664
|
-
def scan_each(options
|
2665
|
-
return to_enum(:scan_each, options) unless block_given?
|
2685
|
+
def scan_each(**options, &block)
|
2686
|
+
return to_enum(:scan_each, **options) unless block_given?
|
2687
|
+
|
2666
2688
|
cursor = 0
|
2667
2689
|
loop do
|
2668
|
-
cursor, keys = scan(cursor, options)
|
2690
|
+
cursor, keys = scan(cursor, **options)
|
2669
2691
|
keys.each(&block)
|
2670
2692
|
break if cursor == "0"
|
2671
2693
|
end
|
@@ -2682,8 +2704,8 @@ class Redis
|
|
2682
2704
|
# - `:count => Integer`: return count keys at most per iteration
|
2683
2705
|
#
|
2684
2706
|
# @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|
|
2707
|
+
def hscan(key, cursor, **options)
|
2708
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2687
2709
|
[reply[0], reply[1].each_slice(2).to_a]
|
2688
2710
|
end
|
2689
2711
|
end
|
@@ -2699,11 +2721,12 @@ class Redis
|
|
2699
2721
|
# - `:count => Integer`: return count keys at most per iteration
|
2700
2722
|
#
|
2701
2723
|
# @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?
|
2724
|
+
def hscan_each(key, **options, &block)
|
2725
|
+
return to_enum(:hscan_each, key, **options) unless block_given?
|
2726
|
+
|
2704
2727
|
cursor = 0
|
2705
2728
|
loop do
|
2706
|
-
cursor, values = hscan(key, cursor, options)
|
2729
|
+
cursor, values = hscan(key, cursor, **options)
|
2707
2730
|
values.each(&block)
|
2708
2731
|
break if cursor == "0"
|
2709
2732
|
end
|
@@ -2721,8 +2744,8 @@ class Redis
|
|
2721
2744
|
#
|
2722
2745
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2723
2746
|
# members and scores
|
2724
|
-
def zscan(key, cursor, options
|
2725
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2747
|
+
def zscan(key, cursor, **options)
|
2748
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2726
2749
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2727
2750
|
end
|
2728
2751
|
end
|
@@ -2738,11 +2761,12 @@ class Redis
|
|
2738
2761
|
# - `:count => Integer`: return count keys at most per iteration
|
2739
2762
|
#
|
2740
2763
|
# @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?
|
2764
|
+
def zscan_each(key, **options, &block)
|
2765
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
2766
|
+
|
2743
2767
|
cursor = 0
|
2744
2768
|
loop do
|
2745
|
-
cursor, values = zscan(key, cursor, options)
|
2769
|
+
cursor, values = zscan(key, cursor, **options)
|
2746
2770
|
values.each(&block)
|
2747
2771
|
break if cursor == "0"
|
2748
2772
|
end
|
@@ -2759,8 +2783,8 @@ class Redis
|
|
2759
2783
|
# - `:count => Integer`: return count keys at most per iteration
|
2760
2784
|
#
|
2761
2785
|
# @return [String, Array<String>] the next cursor and all found members
|
2762
|
-
def sscan(key, cursor, options
|
2763
|
-
_scan(:sscan, cursor, [key], options)
|
2786
|
+
def sscan(key, cursor, **options)
|
2787
|
+
_scan(:sscan, cursor, [key], **options)
|
2764
2788
|
end
|
2765
2789
|
|
2766
2790
|
# Scan a set
|
@@ -2774,11 +2798,12 @@ class Redis
|
|
2774
2798
|
# - `:count => Integer`: return count keys at most per iteration
|
2775
2799
|
#
|
2776
2800
|
# @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?
|
2801
|
+
def sscan_each(key, **options, &block)
|
2802
|
+
return to_enum(:sscan_each, key, **options) unless block_given?
|
2803
|
+
|
2779
2804
|
cursor = 0
|
2780
2805
|
loop do
|
2781
|
-
cursor, keys = sscan(key, cursor, options)
|
2806
|
+
cursor, keys = sscan(key, cursor, **options)
|
2782
2807
|
keys.each(&block)
|
2783
2808
|
break if cursor == "0"
|
2784
2809
|
end
|
@@ -2842,12 +2867,12 @@ class Redis
|
|
2842
2867
|
end
|
2843
2868
|
end
|
2844
2869
|
|
2845
|
-
|
2846
2870
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2847
2871
|
# given maximum distance from a point
|
2848
2872
|
#
|
2849
2873
|
# @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
|
2874
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2875
|
+
# or the farthest to the nearest relative to the center
|
2851
2876
|
# @param [Integer] count limit the results to the first N matching items
|
2852
2877
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2853
2878
|
# @return [Array<String>] may be changed with `options`
|
@@ -2864,7 +2889,8 @@ class Redis
|
|
2864
2889
|
# given maximum distance from an already existing member
|
2865
2890
|
#
|
2866
2891
|
# @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
|
2892
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2893
|
+
# to the nearest relative to the center
|
2868
2894
|
# @param [Integer] count limit the results to the first N matching items
|
2869
2895
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2870
2896
|
# @return [Array<String>] may be changed with `options`
|
@@ -2881,7 +2907,8 @@ class Redis
|
|
2881
2907
|
#
|
2882
2908
|
# @param [String] key
|
2883
2909
|
# @param [String, Array<String>] member one member or array of members
|
2884
|
-
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2910
|
+
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2911
|
+
# element is either array of longitude and latitude or nil
|
2885
2912
|
def geopos(key, member)
|
2886
2913
|
synchronize do |client|
|
2887
2914
|
client.call([:geopos, key, member])
|
@@ -2945,10 +2972,14 @@ class Redis
|
|
2945
2972
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2946
2973
|
#
|
2947
2974
|
# @return [String] the entry id
|
2948
|
-
def xadd(key, entry,
|
2975
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2949
2976
|
args = [:xadd, key]
|
2950
|
-
|
2951
|
-
|
2977
|
+
if maxlen
|
2978
|
+
args << "MAXLEN"
|
2979
|
+
args << "~" if approximate
|
2980
|
+
args << maxlen
|
2981
|
+
end
|
2982
|
+
args << id
|
2952
2983
|
args.concat(entry.to_a.flatten)
|
2953
2984
|
synchronize { |client| client.call(args) }
|
2954
2985
|
end
|
@@ -3003,8 +3034,8 @@ class Redis
|
|
3003
3034
|
# @param count [Integer] the number of entries as limit
|
3004
3035
|
#
|
3005
3036
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3006
|
-
def xrange(key, start = '-',
|
3007
|
-
args = [:xrange, key, start,
|
3037
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3038
|
+
args = [:xrange, key, start, range_end]
|
3008
3039
|
args.concat(['COUNT', count]) if count
|
3009
3040
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3010
3041
|
end
|
@@ -3026,8 +3057,8 @@ class Redis
|
|
3026
3057
|
# @params count [Integer] the number of entries as limit
|
3027
3058
|
#
|
3028
3059
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3029
|
-
def xrevrange(key,
|
3030
|
-
args = [:xrevrange, key,
|
3060
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3061
|
+
args = [:xrevrange, key, range_end, start]
|
3031
3062
|
args.concat(['COUNT', count]) if count
|
3032
3063
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3033
3064
|
end
|
@@ -3119,12 +3150,12 @@ class Redis
|
|
3119
3150
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3120
3151
|
#
|
3121
3152
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3122
|
-
def xreadgroup(group, consumer, keys, ids,
|
3153
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3123
3154
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3124
|
-
args << 'COUNT' <<
|
3125
|
-
args << 'BLOCK' <<
|
3126
|
-
args << 'NOACK' if
|
3127
|
-
_xread(args, keys, ids,
|
3155
|
+
args << 'COUNT' << count if count
|
3156
|
+
args << 'BLOCK' << block.to_i if block
|
3157
|
+
args << 'NOACK' if noack
|
3158
|
+
_xread(args, keys, ids, block)
|
3128
3159
|
end
|
3129
3160
|
|
3130
3161
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3234,8 +3265,8 @@ class Redis
|
|
3234
3265
|
when "get-master-addr-by-name"
|
3235
3266
|
reply
|
3236
3267
|
else
|
3237
|
-
if reply.
|
3238
|
-
if reply[0].
|
3268
|
+
if reply.is_a?(Array)
|
3269
|
+
if reply[0].is_a?(Array)
|
3239
3270
|
reply.map(&Hashify)
|
3240
3271
|
else
|
3241
3272
|
Hashify.call(reply)
|
@@ -3259,12 +3290,17 @@ class Redis
|
|
3259
3290
|
def cluster(subcommand, *args)
|
3260
3291
|
subcommand = subcommand.to_s.downcase
|
3261
3292
|
block = case subcommand
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3293
|
+
when 'slots'
|
3294
|
+
HashifyClusterSlots
|
3295
|
+
when 'nodes'
|
3296
|
+
HashifyClusterNodes
|
3297
|
+
when 'slaves'
|
3298
|
+
HashifyClusterSlaves
|
3299
|
+
when 'info'
|
3300
|
+
HashifyInfo
|
3301
|
+
else
|
3302
|
+
Noop
|
3303
|
+
end
|
3268
3304
|
|
3269
3305
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3270
3306
|
block = Noop unless @cluster_mode
|
@@ -3299,21 +3335,21 @@ class Redis
|
|
3299
3335
|
return @original_client.connection_info if @cluster_mode
|
3300
3336
|
|
3301
3337
|
{
|
3302
|
-
host:
|
3303
|
-
port:
|
3304
|
-
db:
|
3305
|
-
id:
|
3338
|
+
host: @original_client.host,
|
3339
|
+
port: @original_client.port,
|
3340
|
+
db: @original_client.db,
|
3341
|
+
id: @original_client.id,
|
3306
3342
|
location: @original_client.location
|
3307
3343
|
}
|
3308
3344
|
end
|
3309
3345
|
|
3310
|
-
def method_missing(command, *args)
|
3346
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3311
3347
|
synchronize do |client|
|
3312
3348
|
client.call([command] + args)
|
3313
3349
|
end
|
3314
3350
|
end
|
3315
3351
|
|
3316
|
-
private
|
3352
|
+
private
|
3317
3353
|
|
3318
3354
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3319
3355
|
# where the method call will return nil. Propagate the nil instead of falsely
|
@@ -3385,18 +3421,21 @@ private
|
|
3385
3421
|
end
|
3386
3422
|
}
|
3387
3423
|
|
3424
|
+
EMPTY_STREAM_RESPONSE = [nil].freeze
|
3425
|
+
private_constant :EMPTY_STREAM_RESPONSE
|
3426
|
+
|
3388
3427
|
HashifyStreamEntries = lambda { |reply|
|
3389
|
-
reply.map do |entry_id, values|
|
3428
|
+
reply.compact.map do |entry_id, values|
|
3390
3429
|
[entry_id, values.each_slice(2).to_h]
|
3391
3430
|
end
|
3392
3431
|
}
|
3393
3432
|
|
3394
3433
|
HashifyStreamPendings = lambda { |reply|
|
3395
3434
|
{
|
3396
|
-
'size'
|
3435
|
+
'size' => reply[0],
|
3397
3436
|
'min_entry_id' => reply[1],
|
3398
3437
|
'max_entry_id' => reply[2],
|
3399
|
-
'consumers'
|
3438
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3400
3439
|
}
|
3401
3440
|
}
|
3402
3441
|
|
@@ -3405,8 +3444,8 @@ private
|
|
3405
3444
|
{
|
3406
3445
|
'entry_id' => arr[0],
|
3407
3446
|
'consumer' => arr[1],
|
3408
|
-
'elapsed'
|
3409
|
-
'count'
|
3447
|
+
'elapsed' => arr[2],
|
3448
|
+
'count' => arr[3]
|
3410
3449
|
}
|
3411
3450
|
end
|
3412
3451
|
}
|
@@ -3414,15 +3453,15 @@ private
|
|
3414
3453
|
HashifyClusterNodeInfo = lambda { |str|
|
3415
3454
|
arr = str.split(' ')
|
3416
3455
|
{
|
3417
|
-
'node_id'
|
3418
|
-
'ip_port'
|
3419
|
-
'flags'
|
3456
|
+
'node_id' => arr[0],
|
3457
|
+
'ip_port' => arr[1],
|
3458
|
+
'flags' => arr[2].split(','),
|
3420
3459
|
'master_node_id' => arr[3],
|
3421
|
-
'ping_sent'
|
3422
|
-
'pong_recv'
|
3423
|
-
'config_epoch'
|
3424
|
-
'link_state'
|
3425
|
-
'slots'
|
3460
|
+
'ping_sent' => arr[4],
|
3461
|
+
'pong_recv' => arr[5],
|
3462
|
+
'config_epoch' => arr[6],
|
3463
|
+
'link_state' => arr[7],
|
3464
|
+
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3426
3465
|
}
|
3427
3466
|
}
|
3428
3467
|
|
@@ -3433,9 +3472,9 @@ private
|
|
3433
3472
|
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3434
3473
|
{
|
3435
3474
|
'start_slot' => first_slot,
|
3436
|
-
'end_slot'
|
3437
|
-
'master'
|
3438
|
-
'replicas'
|
3475
|
+
'end_slot' => last_slot,
|
3476
|
+
'master' => master,
|
3477
|
+
'replicas' => replicas
|
3439
3478
|
}
|
3440
3479
|
end
|
3441
3480
|
}
|