redis 4.1.4 → 4.2.1
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 +19 -0
- data/README.md +8 -4
- data/lib/redis.rb +275 -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 +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e49d4c950b40f5d702b9b49bfc16b6af12dba334f5866dfd44f1ff69af55ecc
|
4
|
+
data.tar.gz: bf025908a9697cb0308aa3cbce20ecd292a5d9d801c53ad89f739ca5e5beb74f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b27b0178a9120d2843017f5b153dfd48f668ad6b56058bc1058cc318034f1715491cbc9557d71459588b4d3c17970f2572efffd1e79523069ebc4bc208b1c193
|
7
|
+
data.tar.gz: e6ec5a2f2d49bebdef37531d0292f1076bde4ec81adc190eae122d972bb8b9d46354c78c1fc2d1340d392d5805b42a63409bf6fe4cd020c1176a31ed249bc450
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.2.1
|
4
|
+
|
5
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
6
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
7
|
+
|
8
|
+
# 4.2.0
|
9
|
+
|
10
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
11
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
12
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
13
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
14
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
15
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
16
|
+
* Support `keepttl` ooption in `set`. See #913.
|
17
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
18
|
+
* Accept sentinel options even with string key. See #599.
|
19
|
+
* Verify TLS connections by default. See #900.
|
20
|
+
|
3
21
|
# 4.1.4
|
4
22
|
|
5
23
|
* Alias `Redis#disconnect` as `#close`. See #901.
|
@@ -9,6 +27,7 @@
|
|
9
27
|
* Increase buffer size in the ruby connector. See #880.
|
10
28
|
* Fix thread safety of `Redis.queue`. See #878.
|
11
29
|
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
30
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
12
31
|
|
13
32
|
# 4.1.3
|
14
33
|
|
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,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,7 +2438,7 @@ class Redis
|
|
2409
2438
|
end
|
2410
2439
|
|
2411
2440
|
def pipelined
|
2412
|
-
synchronize do |
|
2441
|
+
synchronize do |_client|
|
2413
2442
|
begin
|
2414
2443
|
pipeline = Pipeline.new(@client)
|
2415
2444
|
original, @client = @client, pipeline
|
@@ -2609,18 +2638,12 @@ class Redis
|
|
2609
2638
|
_eval(:evalsha, args)
|
2610
2639
|
end
|
2611
2640
|
|
2612
|
-
def _scan(command, cursor, args,
|
2641
|
+
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2613
2642
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2614
2643
|
|
2615
2644
|
args << cursor
|
2616
|
-
|
2617
|
-
|
2618
|
-
args.concat(["MATCH", match])
|
2619
|
-
end
|
2620
|
-
|
2621
|
-
if count = options[:count]
|
2622
|
-
args.concat(["COUNT", count])
|
2623
|
-
end
|
2645
|
+
args << "MATCH" << match if match
|
2646
|
+
args << "COUNT" << count if count
|
2624
2647
|
|
2625
2648
|
synchronize do |client|
|
2626
2649
|
client.call([command] + args, &block)
|
@@ -2642,8 +2665,8 @@ class Redis
|
|
2642
2665
|
# - `:count => Integer`: return count keys at most per iteration
|
2643
2666
|
#
|
2644
2667
|
# @return [String, Array<String>] the next cursor and all found keys
|
2645
|
-
def scan(cursor, options
|
2646
|
-
_scan(:scan, cursor, [], options)
|
2668
|
+
def scan(cursor, **options)
|
2669
|
+
_scan(:scan, cursor, [], **options)
|
2647
2670
|
end
|
2648
2671
|
|
2649
2672
|
# Scan the keyspace
|
@@ -2661,11 +2684,12 @@ class Redis
|
|
2661
2684
|
# - `:count => Integer`: return count keys at most per iteration
|
2662
2685
|
#
|
2663
2686
|
# @return [Enumerator] an enumerator for all found keys
|
2664
|
-
def scan_each(options
|
2665
|
-
return to_enum(:scan_each, options) unless block_given?
|
2687
|
+
def scan_each(**options, &block)
|
2688
|
+
return to_enum(:scan_each, **options) unless block_given?
|
2689
|
+
|
2666
2690
|
cursor = 0
|
2667
2691
|
loop do
|
2668
|
-
cursor, keys = scan(cursor, options)
|
2692
|
+
cursor, keys = scan(cursor, **options)
|
2669
2693
|
keys.each(&block)
|
2670
2694
|
break if cursor == "0"
|
2671
2695
|
end
|
@@ -2682,8 +2706,8 @@ class Redis
|
|
2682
2706
|
# - `:count => Integer`: return count keys at most per iteration
|
2683
2707
|
#
|
2684
2708
|
# @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|
|
2709
|
+
def hscan(key, cursor, **options)
|
2710
|
+
_scan(:hscan, cursor, [key], **options) do |reply|
|
2687
2711
|
[reply[0], reply[1].each_slice(2).to_a]
|
2688
2712
|
end
|
2689
2713
|
end
|
@@ -2699,11 +2723,12 @@ class Redis
|
|
2699
2723
|
# - `:count => Integer`: return count keys at most per iteration
|
2700
2724
|
#
|
2701
2725
|
# @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?
|
2726
|
+
def hscan_each(key, **options, &block)
|
2727
|
+
return to_enum(:hscan_each, key, **options) unless block_given?
|
2728
|
+
|
2704
2729
|
cursor = 0
|
2705
2730
|
loop do
|
2706
|
-
cursor, values = hscan(key, cursor, options)
|
2731
|
+
cursor, values = hscan(key, cursor, **options)
|
2707
2732
|
values.each(&block)
|
2708
2733
|
break if cursor == "0"
|
2709
2734
|
end
|
@@ -2721,8 +2746,8 @@ class Redis
|
|
2721
2746
|
#
|
2722
2747
|
# @return [String, Array<[String, Float]>] the next cursor and all found
|
2723
2748
|
# members and scores
|
2724
|
-
def zscan(key, cursor, options
|
2725
|
-
_scan(:zscan, cursor, [key], options) do |reply|
|
2749
|
+
def zscan(key, cursor, **options)
|
2750
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
2726
2751
|
[reply[0], FloatifyPairs.call(reply[1])]
|
2727
2752
|
end
|
2728
2753
|
end
|
@@ -2738,11 +2763,12 @@ class Redis
|
|
2738
2763
|
# - `:count => Integer`: return count keys at most per iteration
|
2739
2764
|
#
|
2740
2765
|
# @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?
|
2766
|
+
def zscan_each(key, **options, &block)
|
2767
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
2768
|
+
|
2743
2769
|
cursor = 0
|
2744
2770
|
loop do
|
2745
|
-
cursor, values = zscan(key, cursor, options)
|
2771
|
+
cursor, values = zscan(key, cursor, **options)
|
2746
2772
|
values.each(&block)
|
2747
2773
|
break if cursor == "0"
|
2748
2774
|
end
|
@@ -2759,8 +2785,8 @@ class Redis
|
|
2759
2785
|
# - `:count => Integer`: return count keys at most per iteration
|
2760
2786
|
#
|
2761
2787
|
# @return [String, Array<String>] the next cursor and all found members
|
2762
|
-
def sscan(key, cursor, options
|
2763
|
-
_scan(:sscan, cursor, [key], options)
|
2788
|
+
def sscan(key, cursor, **options)
|
2789
|
+
_scan(:sscan, cursor, [key], **options)
|
2764
2790
|
end
|
2765
2791
|
|
2766
2792
|
# Scan a set
|
@@ -2774,11 +2800,12 @@ class Redis
|
|
2774
2800
|
# - `:count => Integer`: return count keys at most per iteration
|
2775
2801
|
#
|
2776
2802
|
# @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?
|
2803
|
+
def sscan_each(key, **options, &block)
|
2804
|
+
return to_enum(:sscan_each, key, **options) unless block_given?
|
2805
|
+
|
2779
2806
|
cursor = 0
|
2780
2807
|
loop do
|
2781
|
-
cursor, keys = sscan(key, cursor, options)
|
2808
|
+
cursor, keys = sscan(key, cursor, **options)
|
2782
2809
|
keys.each(&block)
|
2783
2810
|
break if cursor == "0"
|
2784
2811
|
end
|
@@ -2842,12 +2869,12 @@ class Redis
|
|
2842
2869
|
end
|
2843
2870
|
end
|
2844
2871
|
|
2845
|
-
|
2846
2872
|
# Query a sorted set representing a geospatial index to fetch members matching a
|
2847
2873
|
# given maximum distance from a point
|
2848
2874
|
#
|
2849
2875
|
# @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
|
2876
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
2877
|
+
# or the farthest to the nearest relative to the center
|
2851
2878
|
# @param [Integer] count limit the results to the first N matching items
|
2852
2879
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2853
2880
|
# @return [Array<String>] may be changed with `options`
|
@@ -2864,7 +2891,8 @@ class Redis
|
|
2864
2891
|
# given maximum distance from an already existing member
|
2865
2892
|
#
|
2866
2893
|
# @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
|
2894
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
2895
|
+
# to the nearest relative to the center
|
2868
2896
|
# @param [Integer] count limit the results to the first N matching items
|
2869
2897
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
2870
2898
|
# @return [Array<String>] may be changed with `options`
|
@@ -2881,7 +2909,8 @@ class Redis
|
|
2881
2909
|
#
|
2882
2910
|
# @param [String] key
|
2883
2911
|
# @param [String, Array<String>] member one member or array of members
|
2884
|
-
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2912
|
+
# @return [Array<Array<String>, nil>] returns array of elements, where each
|
2913
|
+
# element is either array of longitude and latitude or nil
|
2885
2914
|
def geopos(key, member)
|
2886
2915
|
synchronize do |client|
|
2887
2916
|
client.call([:geopos, key, member])
|
@@ -2945,10 +2974,14 @@ class Redis
|
|
2945
2974
|
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
2946
2975
|
#
|
2947
2976
|
# @return [String] the entry id
|
2948
|
-
def xadd(key, entry,
|
2977
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
2949
2978
|
args = [:xadd, key]
|
2950
|
-
|
2951
|
-
|
2979
|
+
if maxlen
|
2980
|
+
args << "MAXLEN"
|
2981
|
+
args << "~" if approximate
|
2982
|
+
args << maxlen
|
2983
|
+
end
|
2984
|
+
args << id
|
2952
2985
|
args.concat(entry.to_a.flatten)
|
2953
2986
|
synchronize { |client| client.call(args) }
|
2954
2987
|
end
|
@@ -3003,8 +3036,8 @@ class Redis
|
|
3003
3036
|
# @param count [Integer] the number of entries as limit
|
3004
3037
|
#
|
3005
3038
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3006
|
-
def xrange(key, start = '-',
|
3007
|
-
args = [:xrange, key, start,
|
3039
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
3040
|
+
args = [:xrange, key, start, range_end]
|
3008
3041
|
args.concat(['COUNT', count]) if count
|
3009
3042
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3010
3043
|
end
|
@@ -3026,8 +3059,8 @@ class Redis
|
|
3026
3059
|
# @params count [Integer] the number of entries as limit
|
3027
3060
|
#
|
3028
3061
|
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
3029
|
-
def xrevrange(key,
|
3030
|
-
args = [:xrevrange, key,
|
3062
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
3063
|
+
args = [:xrevrange, key, range_end, start]
|
3031
3064
|
args.concat(['COUNT', count]) if count
|
3032
3065
|
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
3033
3066
|
end
|
@@ -3119,12 +3152,12 @@ class Redis
|
|
3119
3152
|
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
3120
3153
|
#
|
3121
3154
|
# @return [Hash{String => Hash{String => Hash}}] the entries
|
3122
|
-
def xreadgroup(group, consumer, keys, ids,
|
3155
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
3123
3156
|
args = [:xreadgroup, 'GROUP', group, consumer]
|
3124
|
-
args << 'COUNT' <<
|
3125
|
-
args << 'BLOCK' <<
|
3126
|
-
args << 'NOACK' if
|
3127
|
-
_xread(args, keys, ids,
|
3157
|
+
args << 'COUNT' << count if count
|
3158
|
+
args << 'BLOCK' << block.to_i if block
|
3159
|
+
args << 'NOACK' if noack
|
3160
|
+
_xread(args, keys, ids, block)
|
3128
3161
|
end
|
3129
3162
|
|
3130
3163
|
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
@@ -3234,8 +3267,8 @@ class Redis
|
|
3234
3267
|
when "get-master-addr-by-name"
|
3235
3268
|
reply
|
3236
3269
|
else
|
3237
|
-
if reply.
|
3238
|
-
if reply[0].
|
3270
|
+
if reply.is_a?(Array)
|
3271
|
+
if reply[0].is_a?(Array)
|
3239
3272
|
reply.map(&Hashify)
|
3240
3273
|
else
|
3241
3274
|
Hashify.call(reply)
|
@@ -3259,12 +3292,17 @@ class Redis
|
|
3259
3292
|
def cluster(subcommand, *args)
|
3260
3293
|
subcommand = subcommand.to_s.downcase
|
3261
3294
|
block = case subcommand
|
3262
|
-
|
3263
|
-
|
3264
|
-
|
3265
|
-
|
3266
|
-
|
3267
|
-
|
3295
|
+
when 'slots'
|
3296
|
+
HashifyClusterSlots
|
3297
|
+
when 'nodes'
|
3298
|
+
HashifyClusterNodes
|
3299
|
+
when 'slaves'
|
3300
|
+
HashifyClusterSlaves
|
3301
|
+
when 'info'
|
3302
|
+
HashifyInfo
|
3303
|
+
else
|
3304
|
+
Noop
|
3305
|
+
end
|
3268
3306
|
|
3269
3307
|
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
3270
3308
|
block = Noop unless @cluster_mode
|
@@ -3299,21 +3337,21 @@ class Redis
|
|
3299
3337
|
return @original_client.connection_info if @cluster_mode
|
3300
3338
|
|
3301
3339
|
{
|
3302
|
-
host:
|
3303
|
-
port:
|
3304
|
-
db:
|
3305
|
-
id:
|
3340
|
+
host: @original_client.host,
|
3341
|
+
port: @original_client.port,
|
3342
|
+
db: @original_client.db,
|
3343
|
+
id: @original_client.id,
|
3306
3344
|
location: @original_client.location
|
3307
3345
|
}
|
3308
3346
|
end
|
3309
3347
|
|
3310
|
-
def method_missing(command, *args)
|
3348
|
+
def method_missing(command, *args) # rubocop:disable Style/MissingRespondToMissing
|
3311
3349
|
synchronize do |client|
|
3312
3350
|
client.call([command] + args)
|
3313
3351
|
end
|
3314
3352
|
end
|
3315
3353
|
|
3316
|
-
private
|
3354
|
+
private
|
3317
3355
|
|
3318
3356
|
# Commands returning 1 for true and 0 for false may be executed in a pipeline
|
3319
3357
|
# where the method call will return nil. Propagate the nil instead of falsely
|
@@ -3393,10 +3431,10 @@ private
|
|
3393
3431
|
|
3394
3432
|
HashifyStreamPendings = lambda { |reply|
|
3395
3433
|
{
|
3396
|
-
'size'
|
3434
|
+
'size' => reply[0],
|
3397
3435
|
'min_entry_id' => reply[1],
|
3398
3436
|
'max_entry_id' => reply[2],
|
3399
|
-
'consumers'
|
3437
|
+
'consumers' => reply[3].nil? ? {} : reply[3].to_h
|
3400
3438
|
}
|
3401
3439
|
}
|
3402
3440
|
|
@@ -3405,8 +3443,8 @@ private
|
|
3405
3443
|
{
|
3406
3444
|
'entry_id' => arr[0],
|
3407
3445
|
'consumer' => arr[1],
|
3408
|
-
'elapsed'
|
3409
|
-
'count'
|
3446
|
+
'elapsed' => arr[2],
|
3447
|
+
'count' => arr[3]
|
3410
3448
|
}
|
3411
3449
|
end
|
3412
3450
|
}
|
@@ -3414,15 +3452,15 @@ private
|
|
3414
3452
|
HashifyClusterNodeInfo = lambda { |str|
|
3415
3453
|
arr = str.split(' ')
|
3416
3454
|
{
|
3417
|
-
'node_id'
|
3418
|
-
'ip_port'
|
3419
|
-
'flags'
|
3455
|
+
'node_id' => arr[0],
|
3456
|
+
'ip_port' => arr[1],
|
3457
|
+
'flags' => arr[2].split(','),
|
3420
3458
|
'master_node_id' => arr[3],
|
3421
|
-
'ping_sent'
|
3422
|
-
'pong_recv'
|
3423
|
-
'config_epoch'
|
3424
|
-
'link_state'
|
3425
|
-
'slots'
|
3459
|
+
'ping_sent' => arr[4],
|
3460
|
+
'pong_recv' => arr[5],
|
3461
|
+
'config_epoch' => arr[6],
|
3462
|
+
'link_state' => arr[7],
|
3463
|
+
'slots' => arr[8].nil? ? nil : Range.new(*arr[8].split('-'))
|
3426
3464
|
}
|
3427
3465
|
}
|
3428
3466
|
|
@@ -3433,9 +3471,9 @@ private
|
|
3433
3471
|
replicas = arr[3..-1].map { |r| { 'ip' => r[0], 'port' => r[1], 'node_id' => r[2] } }
|
3434
3472
|
{
|
3435
3473
|
'start_slot' => first_slot,
|
3436
|
-
'end_slot'
|
3437
|
-
'master'
|
3438
|
-
'replicas'
|
3474
|
+
'end_slot' => last_slot,
|
3475
|
+
'master' => master,
|
3476
|
+
'replicas' => replicas
|
3439
3477
|
}
|
3440
3478
|
end
|
3441
3479
|
}
|