redis 4.5.1 → 4.6.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 +51 -0
- data/README.md +10 -10
- data/lib/redis/client.rb +14 -13
- data/lib/redis/cluster/command.rb +4 -6
- data/lib/redis/cluster/node.rb +12 -0
- data/lib/redis/cluster.rb +24 -0
- data/lib/redis/commands/bitmaps.rb +63 -0
- data/lib/redis/commands/cluster.rb +45 -0
- data/lib/redis/commands/connection.rb +58 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +251 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +411 -0
- data/lib/redis/commands/lists.rb +289 -0
- data/lib/redis/commands/pubsub.rb +72 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +207 -0
- data/lib/redis/commands/sorted_sets.rb +804 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +92 -0
- data/lib/redis/commands.rb +242 -0
- data/lib/redis/connection/hiredis.rb +3 -2
- data/lib/redis/connection/ruby.rb +8 -5
- data/lib/redis/connection/synchrony.rb +10 -8
- data/lib/redis/connection.rb +1 -1
- data/lib/redis/distributed.rb +46 -9
- data/lib/redis/pipeline.rb +95 -2
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +133 -3675
- metadata +21 -4
@@ -0,0 +1,804 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Redis
|
4
|
+
module Commands
|
5
|
+
module SortedSets
|
6
|
+
# Get the number of members in a sorted set.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# redis.zcard("zset")
|
10
|
+
# # => 4
|
11
|
+
#
|
12
|
+
# @param [String] key
|
13
|
+
# @return [Integer]
|
14
|
+
def zcard(key)
|
15
|
+
send_command([:zcard, key])
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add one or more members to a sorted set, or update the score for members
|
19
|
+
# that already exist.
|
20
|
+
#
|
21
|
+
# @example Add a single `[score, member]` pair to a sorted set
|
22
|
+
# redis.zadd("zset", 32.0, "member")
|
23
|
+
# @example Add an array of `[score, member]` pairs to a sorted set
|
24
|
+
# redis.zadd("zset", [[32.0, "a"], [64.0, "b"]])
|
25
|
+
#
|
26
|
+
# @param [String] key
|
27
|
+
# @param [[Float, String], Array<[Float, String]>] args
|
28
|
+
# - a single `[score, member]` pair
|
29
|
+
# - an array of `[score, member]` pairs
|
30
|
+
# @param [Hash] options
|
31
|
+
# - `:xx => true`: Only update elements that already exist (never
|
32
|
+
# add elements)
|
33
|
+
# - `:nx => true`: Don't update already existing elements (always
|
34
|
+
# add new elements)
|
35
|
+
# - `:lt => true`: Only update existing elements if the new score
|
36
|
+
# is less than the current score
|
37
|
+
# - `:gt => true`: Only update existing elements if the new score
|
38
|
+
# is greater than the current score
|
39
|
+
# - `:ch => true`: Modify the return value from the number of new
|
40
|
+
# elements added, to the total number of elements changed (CH is an
|
41
|
+
# abbreviation of changed); changed elements are new elements added
|
42
|
+
# and elements already existing for which the score was updated
|
43
|
+
# - `:incr => true`: When this option is specified ZADD acts like
|
44
|
+
# ZINCRBY; only one score-element pair can be specified in this mode
|
45
|
+
#
|
46
|
+
# @return [Boolean, Integer, Float]
|
47
|
+
# - `Boolean` when a single pair is specified, holding whether or not it was
|
48
|
+
# **added** to the sorted set.
|
49
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
50
|
+
# pairs that were **added** to the sorted set.
|
51
|
+
# - `Float` when option :incr is specified, holding the score of the member
|
52
|
+
# after incrementing it.
|
53
|
+
def zadd(key, *args, nx: nil, xx: nil, lt: nil, gt: nil, ch: nil, incr: nil)
|
54
|
+
command = [:zadd, key]
|
55
|
+
command << "NX" if nx
|
56
|
+
command << "XX" if xx
|
57
|
+
command << "LT" if lt
|
58
|
+
command << "GT" if gt
|
59
|
+
command << "CH" if ch
|
60
|
+
command << "INCR" if incr
|
61
|
+
|
62
|
+
if args.size == 1 && args[0].is_a?(Array)
|
63
|
+
# Variadic: return float if INCR, integer if !INCR
|
64
|
+
send_command(command + args[0], &(incr ? Floatify : nil))
|
65
|
+
elsif args.size == 2
|
66
|
+
# Single pair: return float if INCR, boolean if !INCR
|
67
|
+
send_command(command + args, &(incr ? Floatify : Boolify))
|
68
|
+
else
|
69
|
+
raise ArgumentError, "wrong number of arguments"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Increment the score of a member in a sorted set.
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
# redis.zincrby("zset", 32.0, "a")
|
77
|
+
# # => 64.0
|
78
|
+
#
|
79
|
+
# @param [String] key
|
80
|
+
# @param [Float] increment
|
81
|
+
# @param [String] member
|
82
|
+
# @return [Float] score of the member after incrementing it
|
83
|
+
def zincrby(key, increment, member)
|
84
|
+
send_command([:zincrby, key, increment, member], &Floatify)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Remove one or more members from a sorted set.
|
88
|
+
#
|
89
|
+
# @example Remove a single member from a sorted set
|
90
|
+
# redis.zrem("zset", "a")
|
91
|
+
# @example Remove an array of members from a sorted set
|
92
|
+
# redis.zrem("zset", ["a", "b"])
|
93
|
+
#
|
94
|
+
# @param [String] key
|
95
|
+
# @param [String, Array<String>] member
|
96
|
+
# - a single member
|
97
|
+
# - an array of members
|
98
|
+
#
|
99
|
+
# @return [Boolean, Integer]
|
100
|
+
# - `Boolean` when a single member is specified, holding whether or not it
|
101
|
+
# was removed from the sorted set
|
102
|
+
# - `Integer` when an array of pairs is specified, holding the number of
|
103
|
+
# members that were removed to the sorted set
|
104
|
+
def zrem(key, member)
|
105
|
+
send_command([:zrem, key, member]) do |reply|
|
106
|
+
if member.is_a? Array
|
107
|
+
# Variadic: return integer
|
108
|
+
reply
|
109
|
+
else
|
110
|
+
# Single argument: return boolean
|
111
|
+
Boolify.call(reply)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Removes and returns up to count members with the highest scores in the sorted set stored at key.
|
117
|
+
#
|
118
|
+
# @example Popping a member
|
119
|
+
# redis.zpopmax('zset')
|
120
|
+
# #=> ['b', 2.0]
|
121
|
+
# @example With count option
|
122
|
+
# redis.zpopmax('zset', 2)
|
123
|
+
# #=> [['b', 2.0], ['a', 1.0]]
|
124
|
+
#
|
125
|
+
# @params key [String] a key of the sorted set
|
126
|
+
# @params count [Integer] a number of members
|
127
|
+
#
|
128
|
+
# @return [Array<String, Float>] element and score pair if count is not specified
|
129
|
+
# @return [Array<Array<String, Float>>] list of popped elements and scores
|
130
|
+
def zpopmax(key, count = nil)
|
131
|
+
send_command([:zpopmax, key, count].compact) do |members|
|
132
|
+
members = FloatifyPairs.call(members)
|
133
|
+
count.to_i > 1 ? members : members.first
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Removes and returns up to count members with the lowest scores in the sorted set stored at key.
|
138
|
+
#
|
139
|
+
# @example Popping a member
|
140
|
+
# redis.zpopmin('zset')
|
141
|
+
# #=> ['a', 1.0]
|
142
|
+
# @example With count option
|
143
|
+
# redis.zpopmin('zset', 2)
|
144
|
+
# #=> [['a', 1.0], ['b', 2.0]]
|
145
|
+
#
|
146
|
+
# @params key [String] a key of the sorted set
|
147
|
+
# @params count [Integer] a number of members
|
148
|
+
#
|
149
|
+
# @return [Array<String, Float>] element and score pair if count is not specified
|
150
|
+
# @return [Array<Array<String, Float>>] list of popped elements and scores
|
151
|
+
def zpopmin(key, count = nil)
|
152
|
+
send_command([:zpopmin, key, count].compact) do |members|
|
153
|
+
members = FloatifyPairs.call(members)
|
154
|
+
count.to_i > 1 ? members : members.first
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Removes and returns up to count members with the highest scores in the sorted set stored at keys,
|
159
|
+
# or block until one is available.
|
160
|
+
#
|
161
|
+
# @example Popping a member from a sorted set
|
162
|
+
# redis.bzpopmax('zset', 1)
|
163
|
+
# #=> ['zset', 'b', 2.0]
|
164
|
+
# @example Popping a member from multiple sorted sets
|
165
|
+
# redis.bzpopmax('zset1', 'zset2', 1)
|
166
|
+
# #=> ['zset1', 'b', 2.0]
|
167
|
+
#
|
168
|
+
# @params keys [Array<String>] one or multiple keys of the sorted sets
|
169
|
+
# @params timeout [Integer] the maximum number of seconds to block
|
170
|
+
#
|
171
|
+
# @return [Array<String, String, Float>] a touple of key, member and score
|
172
|
+
# @return [nil] when no element could be popped and the timeout expired
|
173
|
+
def bzpopmax(*args)
|
174
|
+
_bpop(:bzpopmax, args) do |reply|
|
175
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Removes and returns up to count members with the lowest scores in the sorted set stored at keys,
|
180
|
+
# or block until one is available.
|
181
|
+
#
|
182
|
+
# @example Popping a member from a sorted set
|
183
|
+
# redis.bzpopmin('zset', 1)
|
184
|
+
# #=> ['zset', 'a', 1.0]
|
185
|
+
# @example Popping a member from multiple sorted sets
|
186
|
+
# redis.bzpopmin('zset1', 'zset2', 1)
|
187
|
+
# #=> ['zset1', 'a', 1.0]
|
188
|
+
#
|
189
|
+
# @params keys [Array<String>] one or multiple keys of the sorted sets
|
190
|
+
# @params timeout [Integer] the maximum number of seconds to block
|
191
|
+
#
|
192
|
+
# @return [Array<String, String, Float>] a touple of key, member and score
|
193
|
+
# @return [nil] when no element could be popped and the timeout expired
|
194
|
+
def bzpopmin(*args)
|
195
|
+
_bpop(:bzpopmin, args) do |reply|
|
196
|
+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Get the score associated with the given member in a sorted set.
|
201
|
+
#
|
202
|
+
# @example Get the score for member "a"
|
203
|
+
# redis.zscore("zset", "a")
|
204
|
+
# # => 32.0
|
205
|
+
#
|
206
|
+
# @param [String] key
|
207
|
+
# @param [String] member
|
208
|
+
# @return [Float] score of the member
|
209
|
+
def zscore(key, member)
|
210
|
+
send_command([:zscore, key, member], &Floatify)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Get the scores associated with the given members in a sorted set.
|
214
|
+
#
|
215
|
+
# @example Get the scores for members "a" and "b"
|
216
|
+
# redis.zmscore("zset", "a", "b")
|
217
|
+
# # => [32.0, 48.0]
|
218
|
+
#
|
219
|
+
# @param [String] key
|
220
|
+
# @param [String, Array<String>] members
|
221
|
+
# @return [Array<Float>] scores of the members
|
222
|
+
def zmscore(key, *members)
|
223
|
+
send_command([:zmscore, key, *members]) do |reply|
|
224
|
+
reply.map(&Floatify)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Get one or more random members from a sorted set.
|
229
|
+
#
|
230
|
+
# @example Get one random member
|
231
|
+
# redis.zrandmember("zset")
|
232
|
+
# # => "a"
|
233
|
+
# @example Get multiple random members
|
234
|
+
# redis.zrandmember("zset", 2)
|
235
|
+
# # => ["a", "b"]
|
236
|
+
# @example Get multiple random members with scores
|
237
|
+
# redis.zrandmember("zset", 2, with_scores: true)
|
238
|
+
# # => [["a", 2.0], ["b", 3.0]]
|
239
|
+
#
|
240
|
+
# @param [String] key
|
241
|
+
# @param [Integer] count
|
242
|
+
# @param [Hash] options
|
243
|
+
# - `:with_scores => true`: include scores in output
|
244
|
+
#
|
245
|
+
# @return [nil, String, Array<String>, Array<[String, Float]>]
|
246
|
+
# - when `key` does not exist or set is empty, `nil`
|
247
|
+
# - when `count` is not specified, a member
|
248
|
+
# - when `count` is specified and `:with_scores` is not specified, an array of members
|
249
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
250
|
+
def zrandmember(key, count = nil, withscores: false, with_scores: withscores)
|
251
|
+
if with_scores && count.nil?
|
252
|
+
raise ArgumentError, "count argument must be specified"
|
253
|
+
end
|
254
|
+
|
255
|
+
args = [:zrandmember, key]
|
256
|
+
args << count if count
|
257
|
+
|
258
|
+
if with_scores
|
259
|
+
args << "WITHSCORES"
|
260
|
+
block = FloatifyPairs
|
261
|
+
end
|
262
|
+
|
263
|
+
send_command(args, &block)
|
264
|
+
end
|
265
|
+
|
266
|
+
# Return a range of members in a sorted set, by index, score or lexicographical ordering.
|
267
|
+
#
|
268
|
+
# @example Retrieve all members from a sorted set, by index
|
269
|
+
# redis.zrange("zset", 0, -1)
|
270
|
+
# # => ["a", "b"]
|
271
|
+
# @example Retrieve all members and their scores from a sorted set
|
272
|
+
# redis.zrange("zset", 0, -1, :with_scores => true)
|
273
|
+
# # => [["a", 32.0], ["b", 64.0]]
|
274
|
+
#
|
275
|
+
# @param [String] key
|
276
|
+
# @param [Integer] start start index
|
277
|
+
# @param [Integer] stop stop index
|
278
|
+
# @param [Hash] options
|
279
|
+
# - `:by_score => false`: return members by score
|
280
|
+
# - `:by_lex => false`: return members by lexicographical ordering
|
281
|
+
# - `:rev => false`: reverse the ordering, from highest to lowest
|
282
|
+
# - `:limit => [offset, count]`: skip `offset` members, return a maximum of
|
283
|
+
# `count` members
|
284
|
+
# - `:with_scores => true`: include scores in output
|
285
|
+
#
|
286
|
+
# @return [Array<String>, Array<[String, Float]>]
|
287
|
+
# - when `:with_scores` is not specified, an array of members
|
288
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
289
|
+
def zrange(key, start, stop, byscore: false, by_score: byscore, bylex: false, by_lex: bylex,
|
290
|
+
rev: false, limit: nil, withscores: false, with_scores: withscores)
|
291
|
+
|
292
|
+
if by_score && by_lex
|
293
|
+
raise ArgumentError, "only one of :by_score or :by_lex can be specified"
|
294
|
+
end
|
295
|
+
|
296
|
+
args = [:zrange, key, start, stop]
|
297
|
+
|
298
|
+
if by_score
|
299
|
+
args << "BYSCORE"
|
300
|
+
elsif by_lex
|
301
|
+
args << "BYLEX"
|
302
|
+
end
|
303
|
+
|
304
|
+
args << "REV" if rev
|
305
|
+
|
306
|
+
if limit
|
307
|
+
args << "LIMIT"
|
308
|
+
args.concat(limit)
|
309
|
+
end
|
310
|
+
|
311
|
+
if with_scores
|
312
|
+
args << "WITHSCORES"
|
313
|
+
block = FloatifyPairs
|
314
|
+
end
|
315
|
+
|
316
|
+
send_command(args, &block)
|
317
|
+
end
|
318
|
+
|
319
|
+
# Select a range of members in a sorted set, by index, score or lexicographical ordering
|
320
|
+
# and store the resulting sorted set in a new key.
|
321
|
+
#
|
322
|
+
# @example
|
323
|
+
# redis.zadd("foo", [[1.0, "s1"], [2.0, "s2"], [3.0, "s3"]])
|
324
|
+
# redis.zrangestore("bar", "foo", 0, 1)
|
325
|
+
# # => 2
|
326
|
+
# redis.zrange("bar", 0, -1)
|
327
|
+
# # => ["s1", "s2"]
|
328
|
+
#
|
329
|
+
# @return [Integer] the number of elements in the resulting sorted set
|
330
|
+
# @see #zrange
|
331
|
+
def zrangestore(dest_key, src_key, start, stop, byscore: false, by_score: byscore,
|
332
|
+
bylex: false, by_lex: bylex, rev: false, limit: nil)
|
333
|
+
if by_score && by_lex
|
334
|
+
raise ArgumentError, "only one of :by_score or :by_lex can be specified"
|
335
|
+
end
|
336
|
+
|
337
|
+
args = [:zrangestore, dest_key, src_key, start, stop]
|
338
|
+
|
339
|
+
if by_score
|
340
|
+
args << "BYSCORE"
|
341
|
+
elsif by_lex
|
342
|
+
args << "BYLEX"
|
343
|
+
end
|
344
|
+
|
345
|
+
args << "REV" if rev
|
346
|
+
|
347
|
+
if limit
|
348
|
+
args << "LIMIT"
|
349
|
+
args.concat(limit)
|
350
|
+
end
|
351
|
+
|
352
|
+
send_command(args)
|
353
|
+
end
|
354
|
+
|
355
|
+
# Return a range of members in a sorted set, by index, with scores ordered
|
356
|
+
# from high to low.
|
357
|
+
#
|
358
|
+
# @example Retrieve all members from a sorted set
|
359
|
+
# redis.zrevrange("zset", 0, -1)
|
360
|
+
# # => ["b", "a"]
|
361
|
+
# @example Retrieve all members and their scores from a sorted set
|
362
|
+
# redis.zrevrange("zset", 0, -1, :with_scores => true)
|
363
|
+
# # => [["b", 64.0], ["a", 32.0]]
|
364
|
+
#
|
365
|
+
# @see #zrange
|
366
|
+
def zrevrange(key, start, stop, withscores: false, with_scores: withscores)
|
367
|
+
args = [:zrevrange, key, start, stop]
|
368
|
+
|
369
|
+
if with_scores
|
370
|
+
args << "WITHSCORES"
|
371
|
+
block = FloatifyPairs
|
372
|
+
end
|
373
|
+
|
374
|
+
send_command(args, &block)
|
375
|
+
end
|
376
|
+
|
377
|
+
# Determine the index of a member in a sorted set.
|
378
|
+
#
|
379
|
+
# @param [String] key
|
380
|
+
# @param [String] member
|
381
|
+
# @return [Integer]
|
382
|
+
def zrank(key, member)
|
383
|
+
send_command([:zrank, key, member])
|
384
|
+
end
|
385
|
+
|
386
|
+
# Determine the index of a member in a sorted set, with scores ordered from
|
387
|
+
# high to low.
|
388
|
+
#
|
389
|
+
# @param [String] key
|
390
|
+
# @param [String] member
|
391
|
+
# @return [Integer]
|
392
|
+
def zrevrank(key, member)
|
393
|
+
send_command([:zrevrank, key, member])
|
394
|
+
end
|
395
|
+
|
396
|
+
# Remove all members in a sorted set within the given indexes.
|
397
|
+
#
|
398
|
+
# @example Remove first 5 members
|
399
|
+
# redis.zremrangebyrank("zset", 0, 4)
|
400
|
+
# # => 5
|
401
|
+
# @example Remove last 5 members
|
402
|
+
# redis.zremrangebyrank("zset", -5, -1)
|
403
|
+
# # => 5
|
404
|
+
#
|
405
|
+
# @param [String] key
|
406
|
+
# @param [Integer] start start index
|
407
|
+
# @param [Integer] stop stop index
|
408
|
+
# @return [Integer] number of members that were removed
|
409
|
+
def zremrangebyrank(key, start, stop)
|
410
|
+
send_command([:zremrangebyrank, key, start, stop])
|
411
|
+
end
|
412
|
+
|
413
|
+
# Count the members, with the same score in a sorted set, within the given lexicographical range.
|
414
|
+
#
|
415
|
+
# @example Count members matching a
|
416
|
+
# redis.zlexcount("zset", "[a", "[a\xff")
|
417
|
+
# # => 1
|
418
|
+
# @example Count members matching a-z
|
419
|
+
# redis.zlexcount("zset", "[a", "[z\xff")
|
420
|
+
# # => 26
|
421
|
+
#
|
422
|
+
# @param [String] key
|
423
|
+
# @param [String] min
|
424
|
+
# - inclusive minimum is specified by prefixing `(`
|
425
|
+
# - exclusive minimum is specified by prefixing `[`
|
426
|
+
# @param [String] max
|
427
|
+
# - inclusive maximum is specified by prefixing `(`
|
428
|
+
# - exclusive maximum is specified by prefixing `[`
|
429
|
+
#
|
430
|
+
# @return [Integer] number of members within the specified lexicographical range
|
431
|
+
def zlexcount(key, min, max)
|
432
|
+
send_command([:zlexcount, key, min, max])
|
433
|
+
end
|
434
|
+
|
435
|
+
# Return a range of members with the same score in a sorted set, by lexicographical ordering
|
436
|
+
#
|
437
|
+
# @example Retrieve members matching a
|
438
|
+
# redis.zrangebylex("zset", "[a", "[a\xff")
|
439
|
+
# # => ["aaren", "aarika", "abagael", "abby"]
|
440
|
+
# @example Retrieve the first 2 members matching a
|
441
|
+
# redis.zrangebylex("zset", "[a", "[a\xff", :limit => [0, 2])
|
442
|
+
# # => ["aaren", "aarika"]
|
443
|
+
#
|
444
|
+
# @param [String] key
|
445
|
+
# @param [String] min
|
446
|
+
# - inclusive minimum is specified by prefixing `(`
|
447
|
+
# - exclusive minimum is specified by prefixing `[`
|
448
|
+
# @param [String] max
|
449
|
+
# - inclusive maximum is specified by prefixing `(`
|
450
|
+
# - exclusive maximum is specified by prefixing `[`
|
451
|
+
# @param [Hash] options
|
452
|
+
# - `:limit => [offset, count]`: skip `offset` members, return a maximum of
|
453
|
+
# `count` members
|
454
|
+
#
|
455
|
+
# @return [Array<String>, Array<[String, Float]>]
|
456
|
+
def zrangebylex(key, min, max, limit: nil)
|
457
|
+
args = [:zrangebylex, key, min, max]
|
458
|
+
|
459
|
+
if limit
|
460
|
+
args << "LIMIT"
|
461
|
+
args.concat(limit)
|
462
|
+
end
|
463
|
+
|
464
|
+
send_command(args)
|
465
|
+
end
|
466
|
+
|
467
|
+
# Return a range of members with the same score in a sorted set, by reversed lexicographical ordering.
|
468
|
+
# Apart from the reversed ordering, #zrevrangebylex is similar to #zrangebylex.
|
469
|
+
#
|
470
|
+
# @example Retrieve members matching a
|
471
|
+
# redis.zrevrangebylex("zset", "[a", "[a\xff")
|
472
|
+
# # => ["abbygail", "abby", "abagael", "aaren"]
|
473
|
+
# @example Retrieve the last 2 members matching a
|
474
|
+
# redis.zrevrangebylex("zset", "[a", "[a\xff", :limit => [0, 2])
|
475
|
+
# # => ["abbygail", "abby"]
|
476
|
+
#
|
477
|
+
# @see #zrangebylex
|
478
|
+
def zrevrangebylex(key, max, min, limit: nil)
|
479
|
+
args = [:zrevrangebylex, key, max, min]
|
480
|
+
|
481
|
+
if limit
|
482
|
+
args << "LIMIT"
|
483
|
+
args.concat(limit)
|
484
|
+
end
|
485
|
+
|
486
|
+
send_command(args)
|
487
|
+
end
|
488
|
+
|
489
|
+
# Return a range of members in a sorted set, by score.
|
490
|
+
#
|
491
|
+
# @example Retrieve members with score `>= 5` and `< 100`
|
492
|
+
# redis.zrangebyscore("zset", "5", "(100")
|
493
|
+
# # => ["a", "b"]
|
494
|
+
# @example Retrieve the first 2 members with score `>= 0`
|
495
|
+
# redis.zrangebyscore("zset", "0", "+inf", :limit => [0, 2])
|
496
|
+
# # => ["a", "b"]
|
497
|
+
# @example Retrieve members and their scores with scores `> 5`
|
498
|
+
# redis.zrangebyscore("zset", "(5", "+inf", :with_scores => true)
|
499
|
+
# # => [["a", 32.0], ["b", 64.0]]
|
500
|
+
#
|
501
|
+
# @param [String] key
|
502
|
+
# @param [String] min
|
503
|
+
# - inclusive minimum score is specified verbatim
|
504
|
+
# - exclusive minimum score is specified by prefixing `(`
|
505
|
+
# @param [String] max
|
506
|
+
# - inclusive maximum score is specified verbatim
|
507
|
+
# - exclusive maximum score is specified by prefixing `(`
|
508
|
+
# @param [Hash] options
|
509
|
+
# - `:with_scores => true`: include scores in output
|
510
|
+
# - `:limit => [offset, count]`: skip `offset` members, return a maximum of
|
511
|
+
# `count` members
|
512
|
+
#
|
513
|
+
# @return [Array<String>, Array<[String, Float]>]
|
514
|
+
# - when `:with_scores` is not specified, an array of members
|
515
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
516
|
+
def zrangebyscore(key, min, max, withscores: false, with_scores: withscores, limit: nil)
|
517
|
+
args = [:zrangebyscore, key, min, max]
|
518
|
+
|
519
|
+
if with_scores
|
520
|
+
args << "WITHSCORES"
|
521
|
+
block = FloatifyPairs
|
522
|
+
end
|
523
|
+
|
524
|
+
if limit
|
525
|
+
args << "LIMIT"
|
526
|
+
args.concat(limit)
|
527
|
+
end
|
528
|
+
|
529
|
+
send_command(args, &block)
|
530
|
+
end
|
531
|
+
|
532
|
+
# Return a range of members in a sorted set, by score, with scores ordered
|
533
|
+
# from high to low.
|
534
|
+
#
|
535
|
+
# @example Retrieve members with score `< 100` and `>= 5`
|
536
|
+
# redis.zrevrangebyscore("zset", "(100", "5")
|
537
|
+
# # => ["b", "a"]
|
538
|
+
# @example Retrieve the first 2 members with score `<= 0`
|
539
|
+
# redis.zrevrangebyscore("zset", "0", "-inf", :limit => [0, 2])
|
540
|
+
# # => ["b", "a"]
|
541
|
+
# @example Retrieve members and their scores with scores `> 5`
|
542
|
+
# redis.zrevrangebyscore("zset", "+inf", "(5", :with_scores => true)
|
543
|
+
# # => [["b", 64.0], ["a", 32.0]]
|
544
|
+
#
|
545
|
+
# @see #zrangebyscore
|
546
|
+
def zrevrangebyscore(key, max, min, withscores: false, with_scores: withscores, limit: nil)
|
547
|
+
args = [:zrevrangebyscore, key, max, min]
|
548
|
+
|
549
|
+
if with_scores
|
550
|
+
args << "WITHSCORES"
|
551
|
+
block = FloatifyPairs
|
552
|
+
end
|
553
|
+
|
554
|
+
if limit
|
555
|
+
args << "LIMIT"
|
556
|
+
args.concat(limit)
|
557
|
+
end
|
558
|
+
|
559
|
+
send_command(args, &block)
|
560
|
+
end
|
561
|
+
|
562
|
+
# Remove all members in a sorted set within the given scores.
|
563
|
+
#
|
564
|
+
# @example Remove members with score `>= 5` and `< 100`
|
565
|
+
# redis.zremrangebyscore("zset", "5", "(100")
|
566
|
+
# # => 2
|
567
|
+
# @example Remove members with scores `> 5`
|
568
|
+
# redis.zremrangebyscore("zset", "(5", "+inf")
|
569
|
+
# # => 2
|
570
|
+
#
|
571
|
+
# @param [String] key
|
572
|
+
# @param [String] min
|
573
|
+
# - inclusive minimum score is specified verbatim
|
574
|
+
# - exclusive minimum score is specified by prefixing `(`
|
575
|
+
# @param [String] max
|
576
|
+
# - inclusive maximum score is specified verbatim
|
577
|
+
# - exclusive maximum score is specified by prefixing `(`
|
578
|
+
# @return [Integer] number of members that were removed
|
579
|
+
def zremrangebyscore(key, min, max)
|
580
|
+
send_command([:zremrangebyscore, key, min, max])
|
581
|
+
end
|
582
|
+
|
583
|
+
# Count the members in a sorted set with scores within the given values.
|
584
|
+
#
|
585
|
+
# @example Count members with score `>= 5` and `< 100`
|
586
|
+
# redis.zcount("zset", "5", "(100")
|
587
|
+
# # => 2
|
588
|
+
# @example Count members with scores `> 5`
|
589
|
+
# redis.zcount("zset", "(5", "+inf")
|
590
|
+
# # => 2
|
591
|
+
#
|
592
|
+
# @param [String] key
|
593
|
+
# @param [String] min
|
594
|
+
# - inclusive minimum score is specified verbatim
|
595
|
+
# - exclusive minimum score is specified by prefixing `(`
|
596
|
+
# @param [String] max
|
597
|
+
# - inclusive maximum score is specified verbatim
|
598
|
+
# - exclusive maximum score is specified by prefixing `(`
|
599
|
+
# @return [Integer] number of members in within the specified range
|
600
|
+
def zcount(key, min, max)
|
601
|
+
send_command([:zcount, key, min, max])
|
602
|
+
end
|
603
|
+
|
604
|
+
# Return the intersection of multiple sorted sets
|
605
|
+
#
|
606
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`
|
607
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0])
|
608
|
+
# # => ["v1", "v2"]
|
609
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`, and their scores
|
610
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0], :with_scores => true)
|
611
|
+
# # => [["v1", 3.0], ["v2", 6.0]]
|
612
|
+
#
|
613
|
+
# @param [String, Array<String>] keys one or more keys to intersect
|
614
|
+
# @param [Hash] options
|
615
|
+
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
616
|
+
# sorted sets
|
617
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
618
|
+
# - `:with_scores => true`: include scores in output
|
619
|
+
#
|
620
|
+
# @return [Array<String>, Array<[String, Float]>]
|
621
|
+
# - when `:with_scores` is not specified, an array of members
|
622
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
623
|
+
def zinter(*args)
|
624
|
+
_zsets_operation(:zinter, *args)
|
625
|
+
end
|
626
|
+
ruby2_keywords(:zinter) if respond_to?(:ruby2_keywords, true)
|
627
|
+
|
628
|
+
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
629
|
+
# key.
|
630
|
+
#
|
631
|
+
# @example Compute the intersection of `2*zsetA` with `1*zsetB`, summing their scores
|
632
|
+
# redis.zinterstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
|
633
|
+
# # => 4
|
634
|
+
#
|
635
|
+
# @param [String] destination destination key
|
636
|
+
# @param [Array<String>] keys source keys
|
637
|
+
# @param [Hash] options
|
638
|
+
# - `:weights => [Array<Float>]`: weights to associate with source
|
639
|
+
# sorted sets
|
640
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max)
|
641
|
+
# @return [Integer] number of elements in the resulting sorted set
|
642
|
+
def zinterstore(*args)
|
643
|
+
_zsets_operation_store(:zinterstore, *args)
|
644
|
+
end
|
645
|
+
ruby2_keywords(:zinterstore) if respond_to?(:ruby2_keywords, true)
|
646
|
+
|
647
|
+
# Return the union of multiple sorted sets
|
648
|
+
#
|
649
|
+
# @example Retrieve the union of `2*zsetA` and `1*zsetB`
|
650
|
+
# redis.zunion("zsetA", "zsetB", :weights => [2.0, 1.0])
|
651
|
+
# # => ["v1", "v2"]
|
652
|
+
# @example Retrieve the union of `2*zsetA` and `1*zsetB`, and their scores
|
653
|
+
# redis.zunion("zsetA", "zsetB", :weights => [2.0, 1.0], :with_scores => true)
|
654
|
+
# # => [["v1", 3.0], ["v2", 6.0]]
|
655
|
+
#
|
656
|
+
# @param [String, Array<String>] keys one or more keys to union
|
657
|
+
# @param [Hash] options
|
658
|
+
# - `:weights => [Array<Float>]`: weights to associate with source
|
659
|
+
# sorted sets
|
660
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max)
|
661
|
+
# - `:with_scores => true`: include scores in output
|
662
|
+
#
|
663
|
+
# @return [Array<String>, Array<[String, Float]>]
|
664
|
+
# - when `:with_scores` is not specified, an array of members
|
665
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
666
|
+
def zunion(*args)
|
667
|
+
_zsets_operation(:zunion, *args)
|
668
|
+
end
|
669
|
+
ruby2_keywords(:zunion) if respond_to?(:ruby2_keywords, true)
|
670
|
+
|
671
|
+
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
672
|
+
#
|
673
|
+
# @example Compute the union of `2*zsetA` with `1*zsetB`, summing their scores
|
674
|
+
# redis.zunionstore("zsetC", ["zsetA", "zsetB"], :weights => [2.0, 1.0], :aggregate => "sum")
|
675
|
+
# # => 8
|
676
|
+
#
|
677
|
+
# @param [String] destination destination key
|
678
|
+
# @param [Array<String>] keys source keys
|
679
|
+
# @param [Hash] options
|
680
|
+
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
681
|
+
# sorted sets
|
682
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
683
|
+
# @return [Integer] number of elements in the resulting sorted set
|
684
|
+
def zunionstore(*args)
|
685
|
+
_zsets_operation_store(:zunionstore, *args)
|
686
|
+
end
|
687
|
+
ruby2_keywords(:zunionstore) if respond_to?(:ruby2_keywords, true)
|
688
|
+
|
689
|
+
# Return the difference between the first and all successive input sorted sets
|
690
|
+
#
|
691
|
+
# @example
|
692
|
+
# redis.zadd("zsetA", [[1.0, "v1"], [2.0, "v2"]])
|
693
|
+
# redis.zadd("zsetB", [[3.0, "v2"], [2.0, "v3"]])
|
694
|
+
# redis.zdiff("zsetA", "zsetB")
|
695
|
+
# => ["v1"]
|
696
|
+
# @example With scores
|
697
|
+
# redis.zadd("zsetA", [[1.0, "v1"], [2.0, "v2"]])
|
698
|
+
# redis.zadd("zsetB", [[3.0, "v2"], [2.0, "v3"]])
|
699
|
+
# redis.zdiff("zsetA", "zsetB", :with_scores => true)
|
700
|
+
# => [["v1", 1.0]]
|
701
|
+
#
|
702
|
+
# @param [String, Array<String>] keys one or more keys to compute the difference
|
703
|
+
# @param [Hash] options
|
704
|
+
# - `:with_scores => true`: include scores in output
|
705
|
+
#
|
706
|
+
# @return [Array<String>, Array<[String, Float]>]
|
707
|
+
# - when `:with_scores` is not specified, an array of members
|
708
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
709
|
+
def zdiff(*keys, with_scores: false)
|
710
|
+
_zsets_operation(:zdiff, *keys, with_scores: with_scores)
|
711
|
+
end
|
712
|
+
|
713
|
+
# Compute the difference between the first and all successive input sorted sets
|
714
|
+
# and store the resulting sorted set in a new key
|
715
|
+
#
|
716
|
+
# @example
|
717
|
+
# redis.zadd("zsetA", [[1.0, "v1"], [2.0, "v2"]])
|
718
|
+
# redis.zadd("zsetB", [[3.0, "v2"], [2.0, "v3"]])
|
719
|
+
# redis.zdiffstore("zsetA", "zsetB")
|
720
|
+
# # => 1
|
721
|
+
#
|
722
|
+
# @param [String] destination destination key
|
723
|
+
# @param [Array<String>] keys source keys
|
724
|
+
# @return [Integer] number of elements in the resulting sorted set
|
725
|
+
def zdiffstore(*args)
|
726
|
+
_zsets_operation_store(:zdiffstore, *args)
|
727
|
+
end
|
728
|
+
ruby2_keywords(:zdiffstore) if respond_to?(:ruby2_keywords, true)
|
729
|
+
|
730
|
+
# Scan a sorted set
|
731
|
+
#
|
732
|
+
# @example Retrieve the first batch of key/value pairs in a hash
|
733
|
+
# redis.zscan("zset", 0)
|
734
|
+
#
|
735
|
+
# @param [String, Integer] cursor the cursor of the iteration
|
736
|
+
# @param [Hash] options
|
737
|
+
# - `:match => String`: only return keys matching the pattern
|
738
|
+
# - `:count => Integer`: return count keys at most per iteration
|
739
|
+
#
|
740
|
+
# @return [String, Array<[String, Float]>] the next cursor and all found
|
741
|
+
# members and scores
|
742
|
+
def zscan(key, cursor, **options)
|
743
|
+
_scan(:zscan, cursor, [key], **options) do |reply|
|
744
|
+
[reply[0], FloatifyPairs.call(reply[1])]
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
# Scan a sorted set
|
749
|
+
#
|
750
|
+
# @example Retrieve all of the members/scores in a sorted set
|
751
|
+
# redis.zscan_each("zset").to_a
|
752
|
+
# # => [["key70", "70"], ["key80", "80"]]
|
753
|
+
#
|
754
|
+
# @param [Hash] options
|
755
|
+
# - `:match => String`: only return keys matching the pattern
|
756
|
+
# - `:count => Integer`: return count keys at most per iteration
|
757
|
+
#
|
758
|
+
# @return [Enumerator] an enumerator for all found scores and members
|
759
|
+
def zscan_each(key, **options, &block)
|
760
|
+
return to_enum(:zscan_each, key, **options) unless block_given?
|
761
|
+
|
762
|
+
cursor = 0
|
763
|
+
loop do
|
764
|
+
cursor, values = zscan(key, cursor, **options)
|
765
|
+
values.each(&block)
|
766
|
+
break if cursor == "0"
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
private
|
771
|
+
|
772
|
+
def _zsets_operation(cmd, *keys, weights: nil, aggregate: nil, with_scores: false)
|
773
|
+
command = [cmd, keys.size, *keys]
|
774
|
+
|
775
|
+
if weights
|
776
|
+
command << "WEIGHTS"
|
777
|
+
command.concat(weights)
|
778
|
+
end
|
779
|
+
|
780
|
+
command << "AGGREGATE" << aggregate if aggregate
|
781
|
+
|
782
|
+
if with_scores
|
783
|
+
command << "WITHSCORES"
|
784
|
+
block = FloatifyPairs
|
785
|
+
end
|
786
|
+
|
787
|
+
send_command(command, &block)
|
788
|
+
end
|
789
|
+
|
790
|
+
def _zsets_operation_store(cmd, destination, keys, weights: nil, aggregate: nil)
|
791
|
+
command = [cmd, destination, keys.size, *keys]
|
792
|
+
|
793
|
+
if weights
|
794
|
+
command << "WEIGHTS"
|
795
|
+
command.concat(weights)
|
796
|
+
end
|
797
|
+
|
798
|
+
command << "AGGREGATE" << aggregate if aggregate
|
799
|
+
|
800
|
+
send_command(command)
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|