redis 4.8.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +138 -1
- data/README.md +285 -169
- data/lib/redis/client.rb +116 -611
- data/lib/redis/commands/bitmaps.rb +14 -4
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/geo.rb +109 -7
- data/lib/redis/commands/hashes.rb +179 -8
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +32 -24
- data/lib/redis/commands/lists.rb +167 -25
- data/lib/redis/commands/modules/json.rb +530 -0
- data/lib/redis/commands/modules/search/aggregation.rb +418 -0
- data/lib/redis/commands/modules/search/dialect.rb +14 -0
- data/lib/redis/commands/modules/search/field.rb +306 -0
- data/lib/redis/commands/modules/search/hybrid.rb +359 -0
- data/lib/redis/commands/modules/search/index.rb +351 -0
- data/lib/redis/commands/modules/search/index_definition.rb +114 -0
- data/lib/redis/commands/modules/search/miscellaneous.rb +607 -0
- data/lib/redis/commands/modules/search/query.rb +738 -0
- data/lib/redis/commands/modules/search/result.rb +488 -0
- data/lib/redis/commands/modules/search/schema.rb +211 -0
- data/lib/redis/commands/modules/search.rb +19 -0
- data/lib/redis/commands/pubsub.rb +34 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +76 -40
- data/lib/redis/commands/sorted_sets.rb +128 -19
- data/lib/redis/commands/streams.rb +75 -28
- data/lib/redis/commands/strings.rb +18 -17
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +39 -20
- data/lib/redis/distributed.rb +407 -73
- data/lib/redis/errors.rb +20 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/lib_identity.rb +105 -0
- data/lib/redis/pipeline.rb +47 -222
- data/lib/redis/subscribe.rb +51 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +213 -188
- metadata +25 -59
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -68
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
|
@@ -27,9 +27,13 @@ class Redis
|
|
|
27
27
|
# @param [String] key
|
|
28
28
|
# @param [Integer] start start index
|
|
29
29
|
# @param [Integer] stop stop index
|
|
30
|
+
# @param [String, Symbol] scale the scale of the offset range
|
|
31
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
|
30
32
|
# @return [Integer] the number of bits set to 1
|
|
31
|
-
def bitcount(key, start = 0, stop = -1)
|
|
32
|
-
|
|
33
|
+
def bitcount(key, start = 0, stop = -1, scale: nil)
|
|
34
|
+
command = [:bitcount, key, start, stop]
|
|
35
|
+
command << scale if scale
|
|
36
|
+
send_command(command)
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
# Perform a bitwise operation between strings and store the resulting string in a key.
|
|
@@ -39,7 +43,10 @@ class Redis
|
|
|
39
43
|
# @param [String, Array<String>] keys one or more source keys to perform `operation`
|
|
40
44
|
# @return [Integer] the length of the string stored in `destkey`
|
|
41
45
|
def bitop(operation, destkey, *keys)
|
|
42
|
-
|
|
46
|
+
keys.flatten!(1)
|
|
47
|
+
command = [:bitop, operation, destkey]
|
|
48
|
+
command.concat(keys)
|
|
49
|
+
send_command(command)
|
|
43
50
|
end
|
|
44
51
|
|
|
45
52
|
# Return the position of the first bit set to 1 or 0 in a string.
|
|
@@ -48,14 +55,17 @@ class Redis
|
|
|
48
55
|
# @param [Integer] bit whether to look for the first 1 or 0 bit
|
|
49
56
|
# @param [Integer] start start index
|
|
50
57
|
# @param [Integer] stop stop index
|
|
58
|
+
# @param [String, Symbol] scale the scale of the offset range
|
|
59
|
+
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
|
|
51
60
|
# @return [Integer] the position of the first 1/0 bit.
|
|
52
61
|
# -1 if looking for 1 and it is not found or start and stop are given.
|
|
53
|
-
def bitpos(key, bit, start = nil, stop = nil)
|
|
62
|
+
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
|
|
54
63
|
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
|
|
55
64
|
|
|
56
65
|
command = [:bitpos, key, bit]
|
|
57
66
|
command << start if start
|
|
58
67
|
command << stop if stop
|
|
68
|
+
command << scale if scale
|
|
59
69
|
send_command(command)
|
|
60
70
|
end
|
|
61
71
|
end
|
|
@@ -12,24 +12,7 @@ class Redis
|
|
|
12
12
|
#
|
|
13
13
|
# @return [Object] depends on the subcommand
|
|
14
14
|
def cluster(subcommand, *args)
|
|
15
|
-
subcommand
|
|
16
|
-
block = case subcommand
|
|
17
|
-
when 'slots'
|
|
18
|
-
HashifyClusterSlots
|
|
19
|
-
when 'nodes'
|
|
20
|
-
HashifyClusterNodes
|
|
21
|
-
when 'slaves'
|
|
22
|
-
HashifyClusterSlaves
|
|
23
|
-
when 'info'
|
|
24
|
-
HashifyInfo
|
|
25
|
-
else
|
|
26
|
-
Noop
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# @see https://github.com/antirez/redis/blob/unstable/src/redis-trib.rb#L127 raw reply expected
|
|
30
|
-
block = Noop unless @cluster_mode
|
|
31
|
-
|
|
32
|
-
send_command([:cluster, subcommand] + args, &block)
|
|
15
|
+
send_command([:cluster, subcommand] + args)
|
|
33
16
|
end
|
|
34
17
|
|
|
35
18
|
# Sends `ASKING` command to random node and returns its reply.
|
|
@@ -34,10 +34,7 @@ class Redis
|
|
|
34
34
|
# @param [Integer] db zero-based index of the DB to use (0 to 15)
|
|
35
35
|
# @return [String] `OK`
|
|
36
36
|
def select(db)
|
|
37
|
-
|
|
38
|
-
client.db = db
|
|
39
|
-
client.call([:select, db])
|
|
40
|
-
end
|
|
37
|
+
send_command([:select, db])
|
|
41
38
|
end
|
|
42
39
|
|
|
43
40
|
# Close the connection.
|
|
@@ -45,12 +42,10 @@ class Redis
|
|
|
45
42
|
# @return [String] `OK`
|
|
46
43
|
def quit
|
|
47
44
|
synchronize do |client|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
client.disconnect
|
|
53
|
-
end
|
|
45
|
+
client.call_v([:quit])
|
|
46
|
+
rescue ConnectionError
|
|
47
|
+
ensure
|
|
48
|
+
client.close
|
|
54
49
|
end
|
|
55
50
|
end
|
|
56
51
|
end
|
data/lib/redis/commands/geo.rb
CHANGED
|
@@ -7,9 +7,19 @@ class Redis
|
|
|
7
7
|
#
|
|
8
8
|
# @param [String] key
|
|
9
9
|
# @param [Array] member arguemnts for member or members: longitude, latitude, name
|
|
10
|
-
# @
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
# @param [Boolean] nx don't update already existing elements, always add new ones (since Redis 6.2)
|
|
11
|
+
# @param [Boolean] xx only update elements that already exist, never add new ones (since Redis 6.2)
|
|
12
|
+
# @param [Boolean] ch modify the return value to the number of changed elements (since Redis 6.2)
|
|
13
|
+
# @return [Integer] number of elements added to the sorted set, or changed when `ch` is set
|
|
14
|
+
def geoadd(key, *member, nx: false, xx: false, ch: false)
|
|
15
|
+
raise ArgumentError, "can't supply both nx and xx" if nx && xx
|
|
16
|
+
|
|
17
|
+
args = [:geoadd, key]
|
|
18
|
+
args << "NX" if nx
|
|
19
|
+
args << "XX" if xx
|
|
20
|
+
args << "CH" if ch
|
|
21
|
+
args.concat(member)
|
|
22
|
+
send_command(args)
|
|
13
23
|
end
|
|
14
24
|
|
|
15
25
|
# Returns geohash string representing position for specified members of the specified key.
|
|
@@ -28,6 +38,7 @@ class Redis
|
|
|
28
38
|
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest
|
|
29
39
|
# or the farthest to the nearest relative to the center
|
|
30
40
|
# @param [Integer] count limit the results to the first N matching items
|
|
41
|
+
# @param [Boolean] count_any return as soon as enough matches found (only with count, since Redis 6.2)
|
|
31
42
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
|
32
43
|
# @return [Array<String>] may be changed with `options`
|
|
33
44
|
def georadius(*args, **geoptions)
|
|
@@ -43,6 +54,7 @@ class Redis
|
|
|
43
54
|
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest or the farthest
|
|
44
55
|
# to the nearest relative to the center
|
|
45
56
|
# @param [Integer] count limit the results to the first N matching items
|
|
57
|
+
# @param [Boolean] count_any return as soon as enough matches found (only with count, since Redis 6.2)
|
|
46
58
|
# @param ['WITHDIST', 'WITHCOORD', 'WITHHASH'] options to return additional information
|
|
47
59
|
# @return [Array<String>] may be changed with `options`
|
|
48
60
|
def georadiusbymember(*args, **geoptions)
|
|
@@ -61,6 +73,93 @@ class Redis
|
|
|
61
73
|
send_command([:geopos, key, member])
|
|
62
74
|
end
|
|
63
75
|
|
|
76
|
+
# Return the members of a geospatial sorted set that are within the borders of the
|
|
77
|
+
# area specified by a given shape, either a circle (BYRADIUS) or a rectangle (BYBOX),
|
|
78
|
+
# starting from a center point given either by member (FROMMEMBER) or by longitude and
|
|
79
|
+
# latitude (FROMLONLAT). Available since Redis 6.2.
|
|
80
|
+
#
|
|
81
|
+
# @example Search by radius from longitude/latitude
|
|
82
|
+
# redis.geosearch("Sicily", fromlonlat: [15, 37], byradius: [200, "km"], sort: "asc")
|
|
83
|
+
# # => ["Catania", "Palermo"]
|
|
84
|
+
#
|
|
85
|
+
# @example Search by box from an existing member, with extras
|
|
86
|
+
# redis.geosearch("Sicily", frommember: "Catania", bybox: [400, 400, "km"],
|
|
87
|
+
# sort: "asc", withcoord: true, withdist: true)
|
|
88
|
+
# # => [["Catania", "0.0000", ["15.087...", "37.502..."]], ...]
|
|
89
|
+
#
|
|
90
|
+
# @param [String] key
|
|
91
|
+
# @param [String] frommember use the position of the given existing member as the center
|
|
92
|
+
# @param [Array<Numeric>] fromlonlat a [longitude, latitude] pair used as the center
|
|
93
|
+
# @param [Array] byradius a [radius, unit] pair where unit is one of 'm', 'km', 'ft', 'mi'
|
|
94
|
+
# @param [Array] bybox a [width, height, unit] triple where unit is one of 'm', 'km', 'ft', 'mi'
|
|
95
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest, or vice versa
|
|
96
|
+
# @param [Integer] count limit the results to the first N matching items
|
|
97
|
+
# @param [Boolean] count_any return as soon as enough matches are found (only with count)
|
|
98
|
+
# @param [Boolean] withcoord also return the longitude and latitude of matching items
|
|
99
|
+
# @param [Boolean] withdist also return the distance from the center point
|
|
100
|
+
# @param [Boolean] withhash also return the raw geohash-encoded sorted set score of the item
|
|
101
|
+
# @return [Array<String>] may be changed with WITH* flags
|
|
102
|
+
def geosearch(key, frommember: nil, fromlonlat: nil, byradius: nil, bybox: nil,
|
|
103
|
+
sort: nil, count: nil, count_any: false,
|
|
104
|
+
withcoord: false, withdist: false, withhash: false)
|
|
105
|
+
args = [key]
|
|
106
|
+
args << "FROMMEMBER" << frommember if frommember
|
|
107
|
+
args << "FROMLONLAT" << fromlonlat[0] << fromlonlat[1] if fromlonlat
|
|
108
|
+
args << "BYRADIUS" << byradius[0] << byradius[1] if byradius
|
|
109
|
+
args << "BYBOX" << bybox[0] << bybox[1] << bybox[2] if bybox
|
|
110
|
+
|
|
111
|
+
options = []
|
|
112
|
+
options << "WITHCOORD" if withcoord
|
|
113
|
+
options << "WITHDIST" if withdist
|
|
114
|
+
options << "WITHHASH" if withhash
|
|
115
|
+
|
|
116
|
+
geoarguments = _geoarguments(*args, sort: sort, count: count, count_any: count_any, options: options)
|
|
117
|
+
|
|
118
|
+
send_command([:geosearch, *geoarguments])
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Like GEOSEARCH, but stores the result in a destination key. By default the destination
|
|
122
|
+
# is populated with the matching members and their geospatial scores; when STOREDIST is
|
|
123
|
+
# set, the members are stored with their distance from the center point as the score.
|
|
124
|
+
# Available since Redis 6.2.
|
|
125
|
+
#
|
|
126
|
+
# @example Store the three nearest members
|
|
127
|
+
# redis.geosearchstore("nearest", "Sicily",
|
|
128
|
+
# fromlonlat: [15, 37], bybox: [400, 400, "km"], sort: "asc", count: 3)
|
|
129
|
+
# # => 3
|
|
130
|
+
#
|
|
131
|
+
# @example Store distances as scores
|
|
132
|
+
# redis.geosearchstore("distances", "Sicily",
|
|
133
|
+
# fromlonlat: [15, 37], bybox: [400, 400, "km"], storedist: true)
|
|
134
|
+
# # => 3
|
|
135
|
+
#
|
|
136
|
+
# @param [String] destination key to store the result in
|
|
137
|
+
# @param [String] source geospatial sorted set to search
|
|
138
|
+
# @param [String] frommember use the position of the given existing member as the center
|
|
139
|
+
# @param [Array<Numeric>] fromlonlat a [longitude, latitude] pair used as the center
|
|
140
|
+
# @param [Array] byradius a [radius, unit] pair where unit is one of 'm', 'km', 'ft', 'mi'
|
|
141
|
+
# @param [Array] bybox a [width, height, unit] triple where unit is one of 'm', 'km', 'ft', 'mi'
|
|
142
|
+
# @param ['asc', 'desc'] sort sort returned items from the nearest to the farthest, or vice versa
|
|
143
|
+
# @param [Integer] count limit the results to the first N matching items
|
|
144
|
+
# @param [Boolean] count_any return as soon as enough matches are found (only with count)
|
|
145
|
+
# @param [Boolean] storedist store the distance from the center point as the score
|
|
146
|
+
# @return [Integer] number of elements stored in the destination key
|
|
147
|
+
def geosearchstore(destination, source, frommember: nil, fromlonlat: nil, byradius: nil, bybox: nil,
|
|
148
|
+
sort: nil, count: nil, count_any: false, storedist: false)
|
|
149
|
+
args = [destination, source]
|
|
150
|
+
args << "FROMMEMBER" << frommember if frommember
|
|
151
|
+
args << "FROMLONLAT" << fromlonlat[0] << fromlonlat[1] if fromlonlat
|
|
152
|
+
args << "BYRADIUS" << byradius[0] << byradius[1] if byradius
|
|
153
|
+
args << "BYBOX" << bybox[0] << bybox[1] << bybox[2] if bybox
|
|
154
|
+
|
|
155
|
+
options = []
|
|
156
|
+
options << "STOREDIST" if storedist
|
|
157
|
+
|
|
158
|
+
geoarguments = _geoarguments(*args, sort: sort, count: count, count_any: count_any, options: options)
|
|
159
|
+
|
|
160
|
+
send_command([:geosearchstore, *geoarguments])
|
|
161
|
+
end
|
|
162
|
+
|
|
64
163
|
# Returns the distance between two members of a geospatial index
|
|
65
164
|
#
|
|
66
165
|
# @param [String ]key
|
|
@@ -73,10 +172,13 @@ class Redis
|
|
|
73
172
|
|
|
74
173
|
private
|
|
75
174
|
|
|
76
|
-
def _geoarguments(*args, options: nil, sort: nil, count: nil)
|
|
77
|
-
args
|
|
78
|
-
|
|
79
|
-
|
|
175
|
+
def _geoarguments(*args, options: nil, sort: nil, count: nil, count_any: false)
|
|
176
|
+
args << sort if sort
|
|
177
|
+
if count
|
|
178
|
+
args << 'COUNT' << Integer(count)
|
|
179
|
+
args << 'ANY' if count_any
|
|
180
|
+
end
|
|
181
|
+
args.concat(Array(options))
|
|
80
182
|
args
|
|
81
183
|
end
|
|
82
184
|
end
|
|
@@ -63,7 +63,7 @@ class Redis
|
|
|
63
63
|
#
|
|
64
64
|
# @see #hmset
|
|
65
65
|
def mapped_hmset(key, hash)
|
|
66
|
-
hmset(key, hash.
|
|
66
|
+
hmset(key, hash.flatten)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
# Get the value of a hash field.
|
|
@@ -87,7 +87,8 @@ class Redis
|
|
|
87
87
|
#
|
|
88
88
|
# @see #mapped_hmget
|
|
89
89
|
def hmget(key, *fields, &blk)
|
|
90
|
-
|
|
90
|
+
fields.flatten!(1)
|
|
91
|
+
send_command([:hmget, key].concat(fields), &blk)
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
# Get the values of all the given hash fields.
|
|
@@ -102,7 +103,8 @@ class Redis
|
|
|
102
103
|
#
|
|
103
104
|
# @see #hmget
|
|
104
105
|
def mapped_hmget(key, *fields)
|
|
105
|
-
|
|
106
|
+
fields.flatten!(1)
|
|
107
|
+
hmget(key, fields) do |reply|
|
|
106
108
|
if reply.is_a?(Array)
|
|
107
109
|
Hash[fields.zip(reply)]
|
|
108
110
|
else
|
|
@@ -152,7 +154,8 @@ class Redis
|
|
|
152
154
|
# @param [String, Array<String>] field
|
|
153
155
|
# @return [Integer] the number of fields that were removed from the hash
|
|
154
156
|
def hdel(key, *fields)
|
|
155
|
-
|
|
157
|
+
fields.flatten!(1)
|
|
158
|
+
send_command([:hdel, key].concat(fields))
|
|
156
159
|
end
|
|
157
160
|
|
|
158
161
|
# Determine if a hash field exists.
|
|
@@ -171,7 +174,7 @@ class Redis
|
|
|
171
174
|
# @param [Integer] increment
|
|
172
175
|
# @return [Integer] value of the field after incrementing it
|
|
173
176
|
def hincrby(key, field, increment)
|
|
174
|
-
send_command([:hincrby, key, field, increment])
|
|
177
|
+
send_command([:hincrby, key, field, Integer(increment)])
|
|
175
178
|
end
|
|
176
179
|
|
|
177
180
|
# Increment the numeric value of a hash field by the given float number.
|
|
@@ -181,7 +184,7 @@ class Redis
|
|
|
181
184
|
# @param [Float] increment
|
|
182
185
|
# @return [Float] value of the field after incrementing it
|
|
183
186
|
def hincrbyfloat(key, field, increment)
|
|
184
|
-
send_command([:hincrbyfloat, key, field, increment], &Floatify)
|
|
187
|
+
send_command([:hincrbyfloat, key, field, Float(increment)], &Floatify)
|
|
185
188
|
end
|
|
186
189
|
|
|
187
190
|
# Get all the fields in a hash.
|
|
@@ -217,11 +220,20 @@ class Redis
|
|
|
217
220
|
# @param [Hash] options
|
|
218
221
|
# - `:match => String`: only return keys matching the pattern
|
|
219
222
|
# - `:count => Integer`: return count keys at most per iteration
|
|
223
|
+
# - `:novalues => Boolean`: whether or not to include values in the output (default: false)
|
|
220
224
|
#
|
|
221
|
-
# @return [String, Array<[String, String]>] the next cursor and all found keys
|
|
225
|
+
# @return [String, Array<[String, String]>, Array<String>] the next cursor and all found keys
|
|
226
|
+
# - when `:novalues` is false: [cursor, [[field1, value1], [field2, value2], ...]]
|
|
227
|
+
# - when `:novalues` is true: [cursor, [field1, field2, ...]]
|
|
228
|
+
#
|
|
229
|
+
# See the [Redis Server HSCAN documentation](https://redis.io/docs/latest/commands/hscan/) for further details
|
|
222
230
|
def hscan(key, cursor, **options)
|
|
223
231
|
_scan(:hscan, cursor, [key], **options) do |reply|
|
|
224
|
-
|
|
232
|
+
if options[:novalues]
|
|
233
|
+
reply
|
|
234
|
+
else
|
|
235
|
+
[reply[0], reply[1].each_slice(2).to_a]
|
|
236
|
+
end
|
|
225
237
|
end
|
|
226
238
|
end
|
|
227
239
|
|
|
@@ -234,8 +246,11 @@ class Redis
|
|
|
234
246
|
# @param [Hash] options
|
|
235
247
|
# - `:match => String`: only return keys matching the pattern
|
|
236
248
|
# - `:count => Integer`: return count keys at most per iteration
|
|
249
|
+
# - `:novalues => Boolean`: whether or not to include values in the output (default: false)
|
|
237
250
|
#
|
|
238
251
|
# @return [Enumerator] an enumerator for all found keys
|
|
252
|
+
#
|
|
253
|
+
# See the [Redis Server HSCAN documentation](https://redis.io/docs/latest/commands/hscan/) for further details
|
|
239
254
|
def hscan_each(key, **options, &block)
|
|
240
255
|
return to_enum(:hscan_each, key, **options) unless block_given?
|
|
241
256
|
|
|
@@ -246,6 +261,162 @@ class Redis
|
|
|
246
261
|
break if cursor == "0"
|
|
247
262
|
end
|
|
248
263
|
end
|
|
264
|
+
|
|
265
|
+
# Sets the time to live in seconds for one or more fields.
|
|
266
|
+
#
|
|
267
|
+
# @example
|
|
268
|
+
# redis.hset("hash", "f1", "v1")
|
|
269
|
+
# redis.hexpire("hash", 10, "f1", "f2") # => [1, -2]
|
|
270
|
+
#
|
|
271
|
+
# @param [String] key
|
|
272
|
+
# @param [Integer] ttl
|
|
273
|
+
# @param [Array<String>] fields
|
|
274
|
+
# @return [Array<Integer>] Feedback on if the fields have been updated.
|
|
275
|
+
#
|
|
276
|
+
# See https://redis.io/docs/latest/commands/hexpire/#return-information for array reply.
|
|
277
|
+
def hexpire(key, ttl, *fields)
|
|
278
|
+
send_command([:hexpire, key, ttl, 'FIELDS', fields.length, *fields])
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Returns the time to live in seconds for one or more fields.
|
|
282
|
+
#
|
|
283
|
+
# @example
|
|
284
|
+
# redis.hset("hash", "f1", "v1", "f2", "v2")
|
|
285
|
+
# redis.hexpire("hash", 10, "f1") # => [1]
|
|
286
|
+
# redis.httl("hash", "f1", "f2", "f3") # => [10, -1, -2]
|
|
287
|
+
#
|
|
288
|
+
# @param [String] key
|
|
289
|
+
# @param [Array<String>] fields
|
|
290
|
+
# @return [Array<Integer>] Feedback on the TTL of the fields.
|
|
291
|
+
#
|
|
292
|
+
# See https://redis.io/docs/latest/commands/httl/#return-information for array reply.
|
|
293
|
+
def httl(key, *fields)
|
|
294
|
+
send_command([:httl, key, 'FIELDS', fields.length, *fields])
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Sets the time to live in milliseconds for one or more fields.
|
|
298
|
+
#
|
|
299
|
+
# @example
|
|
300
|
+
# redis.hset("hash", "f1", "v1")
|
|
301
|
+
# redis.hpexpire("hash", 500, "f1", "f2") # => [1, -2]
|
|
302
|
+
# redis.hpexpire("hash", 500, "f1", "f2", nx: true) # => [0, -2]
|
|
303
|
+
#
|
|
304
|
+
# @param [String] key
|
|
305
|
+
# @param [Integer] ttl
|
|
306
|
+
# @param [Hash] options
|
|
307
|
+
# - `:nx => true`: Set expiry only when the key has no expiry.
|
|
308
|
+
# - `:xx => true`: Set expiry only when the key has an existing expiry.
|
|
309
|
+
# - `:gt => true`: Set expiry only when the new expiry is greater than current one.
|
|
310
|
+
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
|
311
|
+
# @param [Array<String>] fields
|
|
312
|
+
# @return [Array<Integer>] Feedback on if the fields have been updated.
|
|
313
|
+
#
|
|
314
|
+
# See https://redis.io/docs/latest/commands/hpexpire/#return-information for array reply.
|
|
315
|
+
def hpexpire(key, ttl, *fields, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
316
|
+
args = [:hpexpire, key, ttl]
|
|
317
|
+
args << "NX" if nx
|
|
318
|
+
args << "XX" if xx
|
|
319
|
+
args << "GT" if gt
|
|
320
|
+
args << "LT" if lt
|
|
321
|
+
args.concat(['FIELDS', fields.length, *fields])
|
|
322
|
+
|
|
323
|
+
send_command(args)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Returns the time to live in milliseconds for one or more fields.
|
|
327
|
+
#
|
|
328
|
+
# @example
|
|
329
|
+
# redis.hset("hash", "f1", "v1", "f2", "v2")
|
|
330
|
+
# redis.hpexpire("hash", 500, "f1") # => [1]
|
|
331
|
+
# redis.hpttl("hash", "f1", "f2", "f3") # => [500, -1, -2]
|
|
332
|
+
#
|
|
333
|
+
# @param [String] key
|
|
334
|
+
# @param [Array<String>] fields
|
|
335
|
+
# @return [Array<Integer>] Feedback on the TTL of the fields.
|
|
336
|
+
#
|
|
337
|
+
# See https://redis.io/docs/latest/commands/hpttl/#return-information for array reply.
|
|
338
|
+
def hpttl(key, *fields)
|
|
339
|
+
send_command([:hpttl, key, 'FIELDS', fields.length, *fields])
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Register an ordered list of hash field names under +fieldset_name+ for
|
|
343
|
+
# use by subsequent #himport_set calls on the same connection.
|
|
344
|
+
#
|
|
345
|
+
# Fieldsets are server-side session state scoped to the current physical
|
|
346
|
+
# connection: they vanish on disconnect or RESET and are invisible to
|
|
347
|
+
# other connections. See the README "Bulk hash ingestion (HIMPORT)"
|
|
348
|
+
# section for connection-scoping guidance. Re-preparing an existing
|
|
349
|
+
# +fieldset_name+ silently replaces it. Field order is preserved as
|
|
350
|
+
# given; it defines the positional pairing used by #himport_set.
|
|
351
|
+
#
|
|
352
|
+
# @note HIMPORT support is experimental: the client API may change in a
|
|
353
|
+
# future minor release without a major version bump.
|
|
354
|
+
#
|
|
355
|
+
# @example
|
|
356
|
+
# redis.himport_prepare("shared", ["name", "email", "age"])
|
|
357
|
+
# # => "OK"
|
|
358
|
+
#
|
|
359
|
+
# @param [String] fieldset_name name used by later SET and DISCARD calls
|
|
360
|
+
# @param [String, Array<String>] fields one or more field names
|
|
361
|
+
# @return [String] `"OK"`
|
|
362
|
+
# @api experimental
|
|
363
|
+
def himport_prepare(fieldset_name, *fields)
|
|
364
|
+
fields.flatten!(1)
|
|
365
|
+
raise ArgumentError, "fields must not be empty" if fields.empty?
|
|
366
|
+
|
|
367
|
+
send_command([:himport, "PREPARE", fieldset_name].concat(fields))
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Create or fully replace the hash at +key+ using the field list
|
|
371
|
+
# registered under +fieldset_name+ on this connection. Values pair
|
|
372
|
+
# positionally with the fields given to #himport_prepare; the value
|
|
373
|
+
# count must equal the field count.
|
|
374
|
+
#
|
|
375
|
+
# The fieldset must exist on the executing connection, otherwise the
|
|
376
|
+
# server replies with a "no such fieldset" error.
|
|
377
|
+
#
|
|
378
|
+
# @note HIMPORT support is experimental: the client API may change in a
|
|
379
|
+
# future minor release without a major version bump.
|
|
380
|
+
#
|
|
381
|
+
# @example
|
|
382
|
+
# redis.himport_set("shared:1", "shared", ["alice", "alice@example.com", "25"])
|
|
383
|
+
# # => "OK"
|
|
384
|
+
#
|
|
385
|
+
# @param [String] key hash key to create or overwrite
|
|
386
|
+
# @param [String] fieldset_name fieldset previously prepared on this connection
|
|
387
|
+
# @param [String, Array<String>] values one or more values, order preserved
|
|
388
|
+
# @return [String] `"OK"`
|
|
389
|
+
# @api experimental
|
|
390
|
+
def himport_set(key, fieldset_name, *values)
|
|
391
|
+
values.flatten!(1)
|
|
392
|
+
raise ArgumentError, "values must not be empty" if values.empty?
|
|
393
|
+
|
|
394
|
+
send_command([:himport, "SET", key, fieldset_name].concat(values))
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# Remove +fieldset_name+ from this connection's session. Keys already
|
|
398
|
+
# written through the fieldset are not affected.
|
|
399
|
+
#
|
|
400
|
+
# @note HIMPORT support is experimental: the client API may change in a
|
|
401
|
+
# future minor release without a major version bump.
|
|
402
|
+
#
|
|
403
|
+
# @param [String] fieldset_name
|
|
404
|
+
# @return [Integer] `1` if the fieldset was removed, `0` if it did not exist
|
|
405
|
+
# @api experimental
|
|
406
|
+
def himport_discard(fieldset_name)
|
|
407
|
+
send_command([:himport, "DISCARD", fieldset_name])
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Remove all fieldsets from this connection's session.
|
|
411
|
+
#
|
|
412
|
+
# @note HIMPORT support is experimental: the client API may change in a
|
|
413
|
+
# future minor release without a major version bump.
|
|
414
|
+
#
|
|
415
|
+
# @return [Integer] number of fieldsets removed
|
|
416
|
+
# @api experimental
|
|
417
|
+
def himport_discard_all
|
|
418
|
+
send_command([:himport, "DISCARDALL"])
|
|
419
|
+
end
|
|
249
420
|
end
|
|
250
421
|
end
|
|
251
422
|
end
|
|
@@ -20,7 +20,7 @@ class Redis
|
|
|
20
20
|
# @param [String, Array<String>] keys
|
|
21
21
|
# @return [Integer]
|
|
22
22
|
def pfcount(*keys)
|
|
23
|
-
send_command([:pfcount] + keys)
|
|
23
|
+
send_command([:pfcount] + keys.flatten(1))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
|
data/lib/redis/commands/keys.rb
CHANGED
|
@@ -22,6 +22,8 @@ class Redis
|
|
|
22
22
|
# - `:type => String`: return keys only of the given type
|
|
23
23
|
#
|
|
24
24
|
# @return [String, Array<String>] the next cursor and all found keys
|
|
25
|
+
#
|
|
26
|
+
# See the [Redis Server SCAN documentation](https://redis.io/docs/latest/commands/scan/) for further details
|
|
25
27
|
def scan(cursor, **options)
|
|
26
28
|
_scan(:scan, cursor, [], **options)
|
|
27
29
|
end
|
|
@@ -46,6 +48,8 @@ class Redis
|
|
|
46
48
|
# - `:type => String`: return keys only of the given type
|
|
47
49
|
#
|
|
48
50
|
# @return [Enumerator] an enumerator for all found keys
|
|
51
|
+
#
|
|
52
|
+
# See the [Redis Server SCAN documentation](https://redis.io/docs/latest/commands/scan/) for further details
|
|
49
53
|
def scan_each(**options, &block)
|
|
50
54
|
return to_enum(:scan_each, **options) unless block_given?
|
|
51
55
|
|
|
@@ -76,7 +80,7 @@ class Redis
|
|
|
76
80
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
|
77
81
|
# @return [Boolean] whether the timeout was set or not
|
|
78
82
|
def expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
79
|
-
args = [:expire, key, seconds]
|
|
83
|
+
args = [:expire, key, Integer(seconds)]
|
|
80
84
|
args << "NX" if nx
|
|
81
85
|
args << "XX" if xx
|
|
82
86
|
args << "GT" if gt
|
|
@@ -96,7 +100,7 @@ class Redis
|
|
|
96
100
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
|
97
101
|
# @return [Boolean] whether the timeout was set or not
|
|
98
102
|
def expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
99
|
-
args = [:expireat, key, unix_time]
|
|
103
|
+
args = [:expireat, key, Integer(unix_time)]
|
|
100
104
|
args << "NX" if nx
|
|
101
105
|
args << "XX" if xx
|
|
102
106
|
args << "GT" if gt
|
|
@@ -105,6 +109,14 @@ class Redis
|
|
|
105
109
|
send_command(args, &Boolify)
|
|
106
110
|
end
|
|
107
111
|
|
|
112
|
+
# Get a key's expiry time specified as number of seconds from UNIX Epoch
|
|
113
|
+
#
|
|
114
|
+
# @param [String] key
|
|
115
|
+
# @return [Integer] expiry time specified as number of seconds from UNIX Epoch
|
|
116
|
+
def expiretime(key)
|
|
117
|
+
send_command([:expiretime, key])
|
|
118
|
+
end
|
|
119
|
+
|
|
108
120
|
# Get the time to live (in seconds) for a key.
|
|
109
121
|
#
|
|
110
122
|
# @param [String] key
|
|
@@ -132,7 +144,7 @@ class Redis
|
|
|
132
144
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
|
133
145
|
# @return [Boolean] whether the timeout was set or not
|
|
134
146
|
def pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
135
|
-
args = [:pexpire, key, milliseconds]
|
|
147
|
+
args = [:pexpire, key, Integer(milliseconds)]
|
|
136
148
|
args << "NX" if nx
|
|
137
149
|
args << "XX" if xx
|
|
138
150
|
args << "GT" if gt
|
|
@@ -152,7 +164,7 @@ class Redis
|
|
|
152
164
|
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
|
|
153
165
|
# @return [Boolean] whether the timeout was set or not
|
|
154
166
|
def pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
|
|
155
|
-
args = [:pexpireat, key, ms_unix_time]
|
|
167
|
+
args = [:pexpireat, key, Integer(ms_unix_time)]
|
|
156
168
|
args << "NX" if nx
|
|
157
169
|
args << "XX" if xx
|
|
158
170
|
args << "GT" if gt
|
|
@@ -161,6 +173,14 @@ class Redis
|
|
|
161
173
|
send_command(args, &Boolify)
|
|
162
174
|
end
|
|
163
175
|
|
|
176
|
+
# Get a key's expiry time specified as number of milliseconds from UNIX Epoch
|
|
177
|
+
#
|
|
178
|
+
# @param [String] key
|
|
179
|
+
# @return [Integer] expiry time specified as number of milliseconds from UNIX Epoch
|
|
180
|
+
def pexpiretime(key)
|
|
181
|
+
send_command([:pexpiretime, key])
|
|
182
|
+
end
|
|
183
|
+
|
|
164
184
|
# Get the time to live (in milliseconds) for a key.
|
|
165
185
|
#
|
|
166
186
|
# @param [String] key
|
|
@@ -241,6 +261,9 @@ class Redis
|
|
|
241
261
|
# @param [String, Array<String>] keys
|
|
242
262
|
# @return [Integer] number of keys that were unlinked
|
|
243
263
|
def unlink(*keys)
|
|
264
|
+
keys.flatten!(1)
|
|
265
|
+
return 0 if keys.empty?
|
|
266
|
+
|
|
244
267
|
send_command([:unlink] + keys)
|
|
245
268
|
end
|
|
246
269
|
|
|
@@ -249,24 +272,6 @@ class Redis
|
|
|
249
272
|
# @param [String, Array<String>] keys
|
|
250
273
|
# @return [Integer]
|
|
251
274
|
def exists(*keys)
|
|
252
|
-
if !Redis.exists_returns_integer && keys.size == 1
|
|
253
|
-
if Redis.exists_returns_integer.nil?
|
|
254
|
-
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3. `exists?` returns a boolean, you " \
|
|
255
|
-
"should use it instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = " \
|
|
256
|
-
"true. To disable this message and keep the current (boolean) behaviour of 'exists' you can set " \
|
|
257
|
-
"`Redis.exists_returns_integer = false`, but this option will be removed in 5.0.0. " \
|
|
258
|
-
"(#{::Kernel.caller(1, 1).first})\n"
|
|
259
|
-
|
|
260
|
-
::Redis.deprecate!(message)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
exists?(*keys)
|
|
264
|
-
else
|
|
265
|
-
_exists(*keys)
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
def _exists(*keys)
|
|
270
275
|
send_command([:exists, *keys])
|
|
271
276
|
end
|
|
272
277
|
|
|
@@ -284,6 +289,8 @@ class Redis
|
|
|
284
289
|
#
|
|
285
290
|
# @param [String] pattern
|
|
286
291
|
# @return [Array<String>]
|
|
292
|
+
#
|
|
293
|
+
# See the [Redis Server KEYS documentation](https://redis.io/docs/latest/commands/keys/) for further details
|
|
287
294
|
def keys(pattern = "*")
|
|
288
295
|
send_command([:keys, pattern]) do |reply|
|
|
289
296
|
if reply.is_a?(String)
|
|
@@ -440,13 +447,14 @@ class Redis
|
|
|
440
447
|
|
|
441
448
|
private
|
|
442
449
|
|
|
443
|
-
def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
|
|
450
|
+
def _scan(command, cursor, args, match: nil, count: nil, type: nil, novalues: false, &block)
|
|
444
451
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
|
445
452
|
|
|
446
453
|
args << cursor
|
|
447
454
|
args << "MATCH" << match if match
|
|
448
|
-
args << "COUNT" << count if count
|
|
455
|
+
args << "COUNT" << Integer(count) if count
|
|
449
456
|
args << "TYPE" << type if type
|
|
457
|
+
args << "NOVALUES" if novalues
|
|
450
458
|
|
|
451
459
|
send_command([command] + args, &block)
|
|
452
460
|
end
|