redis 4.4.0 → 4.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +96 -0
- data/README.md +25 -10
- data/lib/redis/client.rb +31 -25
- data/lib/redis/cluster/command.rb +4 -6
- data/lib/redis/cluster/command_loader.rb +8 -9
- data/lib/redis/cluster/node.rb +12 -0
- data/lib/redis/cluster/node_loader.rb +8 -11
- data/lib/redis/cluster/option.rb +10 -3
- data/lib/redis/cluster/slot_loader.rb +9 -12
- 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 +455 -0
- data/lib/redis/commands/lists.rb +290 -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 +223 -0
- data/lib/redis/commands/sorted_sets.rb +812 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +139 -0
- data/lib/redis/commands.rb +240 -0
- data/lib/redis/connection/command_helper.rb +2 -0
- data/lib/redis/connection/hiredis.rb +3 -2
- data/lib/redis/connection/ruby.rb +19 -9
- data/lib/redis/connection/synchrony.rb +10 -8
- data/lib/redis/connection.rb +1 -1
- data/lib/redis/distributed.rb +111 -23
- data/lib/redis/errors.rb +9 -0
- data/lib/redis/pipeline.rb +128 -3
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +138 -3482
- metadata +22 -5
@@ -0,0 +1,382 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Redis
|
4
|
+
module Commands
|
5
|
+
module Streams
|
6
|
+
# Returns the stream information each subcommand.
|
7
|
+
#
|
8
|
+
# @example stream
|
9
|
+
# redis.xinfo(:stream, 'mystream')
|
10
|
+
# @example groups
|
11
|
+
# redis.xinfo(:groups, 'mystream')
|
12
|
+
# @example consumers
|
13
|
+
# redis.xinfo(:consumers, 'mystream', 'mygroup')
|
14
|
+
#
|
15
|
+
# @param subcommand [String] e.g. `stream` `groups` `consumers`
|
16
|
+
# @param key [String] the stream key
|
17
|
+
# @param group [String] the consumer group name, required if subcommand is `consumers`
|
18
|
+
#
|
19
|
+
# @return [Hash] information of the stream if subcommand is `stream`
|
20
|
+
# @return [Array<Hash>] information of the consumer groups if subcommand is `groups`
|
21
|
+
# @return [Array<Hash>] information of the consumers if subcommand is `consumers`
|
22
|
+
def xinfo(subcommand, key, group = nil)
|
23
|
+
args = [:xinfo, subcommand, key, group].compact
|
24
|
+
synchronize do |client|
|
25
|
+
client.call(args) do |reply|
|
26
|
+
case subcommand.to_s.downcase
|
27
|
+
when 'stream' then Hashify.call(reply)
|
28
|
+
when 'groups', 'consumers' then reply.map { |arr| Hashify.call(arr) }
|
29
|
+
else reply
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add new entry to the stream.
|
36
|
+
#
|
37
|
+
# @example Without options
|
38
|
+
# redis.xadd('mystream', f1: 'v1', f2: 'v2')
|
39
|
+
# @example With options
|
40
|
+
# redis.xadd('mystream', { f1: 'v1', f2: 'v2' }, id: '0-0', maxlen: 1000, approximate: true)
|
41
|
+
#
|
42
|
+
# @param key [String] the stream key
|
43
|
+
# @param entry [Hash] one or multiple field-value pairs
|
44
|
+
# @param opts [Hash] several options for `XADD` command
|
45
|
+
#
|
46
|
+
# @option opts [String] :id the entry id, default value is `*`, it means auto generation
|
47
|
+
# @option opts [Integer] :maxlen max length of entries
|
48
|
+
# @option opts [Boolean] :approximate whether to add `~` modifier of maxlen or not
|
49
|
+
#
|
50
|
+
# @return [String] the entry id
|
51
|
+
def xadd(key, entry, approximate: nil, maxlen: nil, id: '*')
|
52
|
+
args = [:xadd, key]
|
53
|
+
if maxlen
|
54
|
+
args << "MAXLEN"
|
55
|
+
args << "~" if approximate
|
56
|
+
args << maxlen
|
57
|
+
end
|
58
|
+
args << id
|
59
|
+
args.concat(entry.to_a.flatten)
|
60
|
+
send_command(args)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Trims older entries of the stream if needed.
|
64
|
+
#
|
65
|
+
# @example Without options
|
66
|
+
# redis.xtrim('mystream', 1000)
|
67
|
+
# @example With options
|
68
|
+
# redis.xtrim('mystream', 1000, approximate: true)
|
69
|
+
#
|
70
|
+
# @param key [String] the stream key
|
71
|
+
# @param mexlen [Integer] max length of entries
|
72
|
+
# @param approximate [Boolean] whether to add `~` modifier of maxlen or not
|
73
|
+
#
|
74
|
+
# @return [Integer] the number of entries actually deleted
|
75
|
+
def xtrim(key, maxlen, approximate: false)
|
76
|
+
args = [:xtrim, key, 'MAXLEN', (approximate ? '~' : nil), maxlen].compact
|
77
|
+
send_command(args)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Delete entries by entry ids.
|
81
|
+
#
|
82
|
+
# @example With splatted entry ids
|
83
|
+
# redis.xdel('mystream', '0-1', '0-2')
|
84
|
+
# @example With arrayed entry ids
|
85
|
+
# redis.xdel('mystream', ['0-1', '0-2'])
|
86
|
+
#
|
87
|
+
# @param key [String] the stream key
|
88
|
+
# @param ids [Array<String>] one or multiple entry ids
|
89
|
+
#
|
90
|
+
# @return [Integer] the number of entries actually deleted
|
91
|
+
def xdel(key, *ids)
|
92
|
+
args = [:xdel, key].concat(ids.flatten)
|
93
|
+
send_command(args)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Fetches entries of the stream in ascending order.
|
97
|
+
#
|
98
|
+
# @example Without options
|
99
|
+
# redis.xrange('mystream')
|
100
|
+
# @example With a specific start
|
101
|
+
# redis.xrange('mystream', '0-1')
|
102
|
+
# @example With a specific start and end
|
103
|
+
# redis.xrange('mystream', '0-1', '0-3')
|
104
|
+
# @example With count options
|
105
|
+
# redis.xrange('mystream', count: 10)
|
106
|
+
#
|
107
|
+
# @param key [String] the stream key
|
108
|
+
# @param start [String] first entry id of range, default value is `-`
|
109
|
+
# @param end [String] last entry id of range, default value is `+`
|
110
|
+
# @param count [Integer] the number of entries as limit
|
111
|
+
#
|
112
|
+
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
113
|
+
def xrange(key, start = '-', range_end = '+', count: nil)
|
114
|
+
args = [:xrange, key, start, range_end]
|
115
|
+
args.concat(['COUNT', count]) if count
|
116
|
+
synchronize { |client| client.call(args, &HashifyStreamEntries) }
|
117
|
+
end
|
118
|
+
|
119
|
+
# Fetches entries of the stream in descending order.
|
120
|
+
#
|
121
|
+
# @example Without options
|
122
|
+
# redis.xrevrange('mystream')
|
123
|
+
# @example With a specific end
|
124
|
+
# redis.xrevrange('mystream', '0-3')
|
125
|
+
# @example With a specific end and start
|
126
|
+
# redis.xrevrange('mystream', '0-3', '0-1')
|
127
|
+
# @example With count options
|
128
|
+
# redis.xrevrange('mystream', count: 10)
|
129
|
+
#
|
130
|
+
# @param key [String] the stream key
|
131
|
+
# @param end [String] first entry id of range, default value is `+`
|
132
|
+
# @param start [String] last entry id of range, default value is `-`
|
133
|
+
# @params count [Integer] the number of entries as limit
|
134
|
+
#
|
135
|
+
# @return [Array<Array<String, Hash>>] the ids and entries pairs
|
136
|
+
def xrevrange(key, range_end = '+', start = '-', count: nil)
|
137
|
+
args = [:xrevrange, key, range_end, start]
|
138
|
+
args.concat(['COUNT', count]) if count
|
139
|
+
send_command(args, &HashifyStreamEntries)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the number of entries inside a stream.
|
143
|
+
#
|
144
|
+
# @example With key
|
145
|
+
# redis.xlen('mystream')
|
146
|
+
#
|
147
|
+
# @param key [String] the stream key
|
148
|
+
#
|
149
|
+
# @return [Integer] the number of entries
|
150
|
+
def xlen(key)
|
151
|
+
send_command([:xlen, key])
|
152
|
+
end
|
153
|
+
|
154
|
+
# Fetches entries from one or multiple streams. Optionally blocking.
|
155
|
+
#
|
156
|
+
# @example With a key
|
157
|
+
# redis.xread('mystream', '0-0')
|
158
|
+
# @example With multiple keys
|
159
|
+
# redis.xread(%w[mystream1 mystream2], %w[0-0 0-0])
|
160
|
+
# @example With count option
|
161
|
+
# redis.xread('mystream', '0-0', count: 2)
|
162
|
+
# @example With block option
|
163
|
+
# redis.xread('mystream', '$', block: 1000)
|
164
|
+
#
|
165
|
+
# @param keys [Array<String>] one or multiple stream keys
|
166
|
+
# @param ids [Array<String>] one or multiple entry ids
|
167
|
+
# @param count [Integer] the number of entries as limit per stream
|
168
|
+
# @param block [Integer] the number of milliseconds as blocking timeout
|
169
|
+
#
|
170
|
+
# @return [Hash{String => Hash{String => Hash}}] the entries
|
171
|
+
def xread(keys, ids, count: nil, block: nil)
|
172
|
+
args = [:xread]
|
173
|
+
args << 'COUNT' << count if count
|
174
|
+
args << 'BLOCK' << block.to_i if block
|
175
|
+
_xread(args, keys, ids, block)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Manages the consumer group of the stream.
|
179
|
+
#
|
180
|
+
# @example With `create` subcommand
|
181
|
+
# redis.xgroup(:create, 'mystream', 'mygroup', '$')
|
182
|
+
# @example With `setid` subcommand
|
183
|
+
# redis.xgroup(:setid, 'mystream', 'mygroup', '$')
|
184
|
+
# @example With `destroy` subcommand
|
185
|
+
# redis.xgroup(:destroy, 'mystream', 'mygroup')
|
186
|
+
# @example With `delconsumer` subcommand
|
187
|
+
# redis.xgroup(:delconsumer, 'mystream', 'mygroup', 'consumer1')
|
188
|
+
#
|
189
|
+
# @param subcommand [String] `create` `setid` `destroy` `delconsumer`
|
190
|
+
# @param key [String] the stream key
|
191
|
+
# @param group [String] the consumer group name
|
192
|
+
# @param id_or_consumer [String]
|
193
|
+
# * the entry id or `$`, required if subcommand is `create` or `setid`
|
194
|
+
# * the consumer name, required if subcommand is `delconsumer`
|
195
|
+
# @param mkstream [Boolean] whether to create an empty stream automatically or not
|
196
|
+
#
|
197
|
+
# @return [String] `OK` if subcommand is `create` or `setid`
|
198
|
+
# @return [Integer] effected count if subcommand is `destroy` or `delconsumer`
|
199
|
+
def xgroup(subcommand, key, group, id_or_consumer = nil, mkstream: false)
|
200
|
+
args = [:xgroup, subcommand, key, group, id_or_consumer, (mkstream ? 'MKSTREAM' : nil)].compact
|
201
|
+
send_command(args)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Fetches a subset of the entries from one or multiple streams related with the consumer group.
|
205
|
+
# Optionally blocking.
|
206
|
+
#
|
207
|
+
# @example With a key
|
208
|
+
# redis.xreadgroup('mygroup', 'consumer1', 'mystream', '>')
|
209
|
+
# @example With multiple keys
|
210
|
+
# redis.xreadgroup('mygroup', 'consumer1', %w[mystream1 mystream2], %w[> >])
|
211
|
+
# @example With count option
|
212
|
+
# redis.xreadgroup('mygroup', 'consumer1', 'mystream', '>', count: 2)
|
213
|
+
# @example With block option
|
214
|
+
# redis.xreadgroup('mygroup', 'consumer1', 'mystream', '>', block: 1000)
|
215
|
+
# @example With noack option
|
216
|
+
# redis.xreadgroup('mygroup', 'consumer1', 'mystream', '>', noack: true)
|
217
|
+
#
|
218
|
+
# @param group [String] the consumer group name
|
219
|
+
# @param consumer [String] the consumer name
|
220
|
+
# @param keys [Array<String>] one or multiple stream keys
|
221
|
+
# @param ids [Array<String>] one or multiple entry ids
|
222
|
+
# @param opts [Hash] several options for `XREADGROUP` command
|
223
|
+
#
|
224
|
+
# @option opts [Integer] :count the number of entries as limit
|
225
|
+
# @option opts [Integer] :block the number of milliseconds as blocking timeout
|
226
|
+
# @option opts [Boolean] :noack whether message loss is acceptable or not
|
227
|
+
#
|
228
|
+
# @return [Hash{String => Hash{String => Hash}}] the entries
|
229
|
+
def xreadgroup(group, consumer, keys, ids, count: nil, block: nil, noack: nil)
|
230
|
+
args = [:xreadgroup, 'GROUP', group, consumer]
|
231
|
+
args << 'COUNT' << count if count
|
232
|
+
args << 'BLOCK' << block.to_i if block
|
233
|
+
args << 'NOACK' if noack
|
234
|
+
_xread(args, keys, ids, block)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Removes one or multiple entries from the pending entries list of a stream consumer group.
|
238
|
+
#
|
239
|
+
# @example With a entry id
|
240
|
+
# redis.xack('mystream', 'mygroup', '1526569495631-0')
|
241
|
+
# @example With splatted entry ids
|
242
|
+
# redis.xack('mystream', 'mygroup', '0-1', '0-2')
|
243
|
+
# @example With arrayed entry ids
|
244
|
+
# redis.xack('mystream', 'mygroup', %w[0-1 0-2])
|
245
|
+
#
|
246
|
+
# @param key [String] the stream key
|
247
|
+
# @param group [String] the consumer group name
|
248
|
+
# @param ids [Array<String>] one or multiple entry ids
|
249
|
+
#
|
250
|
+
# @return [Integer] the number of entries successfully acknowledged
|
251
|
+
def xack(key, group, *ids)
|
252
|
+
args = [:xack, key, group].concat(ids.flatten)
|
253
|
+
send_command(args)
|
254
|
+
end
|
255
|
+
|
256
|
+
# Changes the ownership of a pending entry
|
257
|
+
#
|
258
|
+
# @example With splatted entry ids
|
259
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-1', '0-2')
|
260
|
+
# @example With arrayed entry ids
|
261
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2])
|
262
|
+
# @example With idle option
|
263
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2], idle: 1000)
|
264
|
+
# @example With time option
|
265
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2], time: 1542866959000)
|
266
|
+
# @example With retrycount option
|
267
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2], retrycount: 10)
|
268
|
+
# @example With force option
|
269
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2], force: true)
|
270
|
+
# @example With justid option
|
271
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, %w[0-1 0-2], justid: true)
|
272
|
+
#
|
273
|
+
# @param key [String] the stream key
|
274
|
+
# @param group [String] the consumer group name
|
275
|
+
# @param consumer [String] the consumer name
|
276
|
+
# @param min_idle_time [Integer] the number of milliseconds
|
277
|
+
# @param ids [Array<String>] one or multiple entry ids
|
278
|
+
# @param opts [Hash] several options for `XCLAIM` command
|
279
|
+
#
|
280
|
+
# @option opts [Integer] :idle the number of milliseconds as last time it was delivered of the entry
|
281
|
+
# @option opts [Integer] :time the number of milliseconds as a specific Unix Epoch time
|
282
|
+
# @option opts [Integer] :retrycount the number of retry counter
|
283
|
+
# @option opts [Boolean] :force whether to create the pending entry to the pending entries list or not
|
284
|
+
# @option opts [Boolean] :justid whether to fetch just an array of entry ids or not
|
285
|
+
#
|
286
|
+
# @return [Hash{String => Hash}] the entries successfully claimed
|
287
|
+
# @return [Array<String>] the entry ids successfully claimed if justid option is `true`
|
288
|
+
def xclaim(key, group, consumer, min_idle_time, *ids, **opts)
|
289
|
+
args = [:xclaim, key, group, consumer, min_idle_time].concat(ids.flatten)
|
290
|
+
args.concat(['IDLE', opts[:idle].to_i]) if opts[:idle]
|
291
|
+
args.concat(['TIME', opts[:time].to_i]) if opts[:time]
|
292
|
+
args.concat(['RETRYCOUNT', opts[:retrycount]]) if opts[:retrycount]
|
293
|
+
args << 'FORCE' if opts[:force]
|
294
|
+
args << 'JUSTID' if opts[:justid]
|
295
|
+
blk = opts[:justid] ? Noop : HashifyStreamEntries
|
296
|
+
send_command(args, &blk)
|
297
|
+
end
|
298
|
+
|
299
|
+
# Transfers ownership of pending stream entries that match the specified criteria.
|
300
|
+
#
|
301
|
+
# @example Claim next pending message stuck > 5 minutes and mark as retry
|
302
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0')
|
303
|
+
# @example Claim 50 next pending messages stuck > 5 minutes and mark as retry
|
304
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', count: 50)
|
305
|
+
# @example Claim next pending message stuck > 5 minutes and don't mark as retry
|
306
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', justid: true)
|
307
|
+
# @example Claim next pending message after this id stuck > 5 minutes and mark as retry
|
308
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '1641321233-0')
|
309
|
+
#
|
310
|
+
# @param key [String] the stream key
|
311
|
+
# @param group [String] the consumer group name
|
312
|
+
# @param consumer [String] the consumer name
|
313
|
+
# @param min_idle_time [Integer] the number of milliseconds
|
314
|
+
# @param start [String] entry id to start scanning from or 0-0 for everything
|
315
|
+
# @param count [Integer] number of messages to claim (default 1)
|
316
|
+
# @param justid [Boolean] whether to fetch just an array of entry ids or not.
|
317
|
+
# Does not increment retry count when true
|
318
|
+
#
|
319
|
+
# @return [Hash{String => Hash}] the entries successfully claimed
|
320
|
+
# @return [Array<String>] the entry ids successfully claimed if justid option is `true`
|
321
|
+
def xautoclaim(key, group, consumer, min_idle_time, start, count: nil, justid: false)
|
322
|
+
args = [:xautoclaim, key, group, consumer, min_idle_time, start]
|
323
|
+
if count
|
324
|
+
args << 'COUNT' << count.to_s
|
325
|
+
end
|
326
|
+
args << 'JUSTID' if justid
|
327
|
+
blk = justid ? HashifyStreamAutoclaimJustId : HashifyStreamAutoclaim
|
328
|
+
send_command(args, &blk)
|
329
|
+
end
|
330
|
+
|
331
|
+
# Fetches not acknowledging pending entries
|
332
|
+
#
|
333
|
+
# @example With key and group
|
334
|
+
# redis.xpending('mystream', 'mygroup')
|
335
|
+
# @example With range options
|
336
|
+
# redis.xpending('mystream', 'mygroup', '-', '+', 10)
|
337
|
+
# @example With range and consumer options
|
338
|
+
# redis.xpending('mystream', 'mygroup', '-', '+', 10, 'consumer1')
|
339
|
+
#
|
340
|
+
# @param key [String] the stream key
|
341
|
+
# @param group [String] the consumer group name
|
342
|
+
# @param start [String] start first entry id of range
|
343
|
+
# @param end [String] end last entry id of range
|
344
|
+
# @param count [Integer] count the number of entries as limit
|
345
|
+
# @param consumer [String] the consumer name
|
346
|
+
#
|
347
|
+
# @return [Hash] the summary of pending entries
|
348
|
+
# @return [Array<Hash>] the pending entries details if options were specified
|
349
|
+
def xpending(key, group, *args)
|
350
|
+
command_args = [:xpending, key, group]
|
351
|
+
case args.size
|
352
|
+
when 0, 3, 4
|
353
|
+
command_args.concat(args)
|
354
|
+
else
|
355
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size + 2}, expected 2, 5 or 6)"
|
356
|
+
end
|
357
|
+
|
358
|
+
summary_needed = args.empty?
|
359
|
+
blk = summary_needed ? HashifyStreamPendings : HashifyStreamPendingDetails
|
360
|
+
send_command(command_args, &blk)
|
361
|
+
end
|
362
|
+
|
363
|
+
private
|
364
|
+
|
365
|
+
def _xread(args, keys, ids, blocking_timeout_msec)
|
366
|
+
keys = keys.is_a?(Array) ? keys : [keys]
|
367
|
+
ids = ids.is_a?(Array) ? ids : [ids]
|
368
|
+
args << 'STREAMS'
|
369
|
+
args.concat(keys)
|
370
|
+
args.concat(ids)
|
371
|
+
|
372
|
+
if blocking_timeout_msec.nil?
|
373
|
+
send_command(args, &HashifyStreams)
|
374
|
+
elsif blocking_timeout_msec.to_f.zero?
|
375
|
+
send_blocking_command(args, 0, &HashifyStreams)
|
376
|
+
else
|
377
|
+
send_blocking_command(args, blocking_timeout_msec.to_f / 1_000, &HashifyStreams)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
@@ -0,0 +1,313 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Redis
|
4
|
+
module Commands
|
5
|
+
module Strings
|
6
|
+
# Decrement the integer value of a key by one.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# redis.decr("value")
|
10
|
+
# # => 4
|
11
|
+
#
|
12
|
+
# @param [String] key
|
13
|
+
# @return [Integer] value after decrementing it
|
14
|
+
def decr(key)
|
15
|
+
send_command([:decr, key])
|
16
|
+
end
|
17
|
+
|
18
|
+
# Decrement the integer value of a key by the given number.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# redis.decrby("value", 5)
|
22
|
+
# # => 0
|
23
|
+
#
|
24
|
+
# @param [String] key
|
25
|
+
# @param [Integer] decrement
|
26
|
+
# @return [Integer] value after decrementing it
|
27
|
+
def decrby(key, decrement)
|
28
|
+
send_command([:decrby, key, decrement])
|
29
|
+
end
|
30
|
+
|
31
|
+
# Increment the integer value of a key by one.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# redis.incr("value")
|
35
|
+
# # => 6
|
36
|
+
#
|
37
|
+
# @param [String] key
|
38
|
+
# @return [Integer] value after incrementing it
|
39
|
+
def incr(key)
|
40
|
+
send_command([:incr, key])
|
41
|
+
end
|
42
|
+
|
43
|
+
# Increment the integer value of a key by the given integer number.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# redis.incrby("value", 5)
|
47
|
+
# # => 10
|
48
|
+
#
|
49
|
+
# @param [String] key
|
50
|
+
# @param [Integer] increment
|
51
|
+
# @return [Integer] value after incrementing it
|
52
|
+
def incrby(key, increment)
|
53
|
+
send_command([:incrby, key, increment])
|
54
|
+
end
|
55
|
+
|
56
|
+
# Increment the numeric value of a key by the given float number.
|
57
|
+
#
|
58
|
+
# @example
|
59
|
+
# redis.incrbyfloat("value", 1.23)
|
60
|
+
# # => 1.23
|
61
|
+
#
|
62
|
+
# @param [String] key
|
63
|
+
# @param [Float] increment
|
64
|
+
# @return [Float] value after incrementing it
|
65
|
+
def incrbyfloat(key, increment)
|
66
|
+
send_command([:incrbyfloat, key, increment], &Floatify)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Set the string value of a key.
|
70
|
+
#
|
71
|
+
# @param [String] key
|
72
|
+
# @param [String] value
|
73
|
+
# @param [Hash] options
|
74
|
+
# - `:ex => Integer`: Set the specified expire time, in seconds.
|
75
|
+
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
76
|
+
# - `:exat => Integer` : Set the specified Unix time at which the key will expire, in seconds.
|
77
|
+
# - `:pxat => Integer` : Set the specified Unix time at which the key will expire, in milliseconds.
|
78
|
+
# - `:nx => true`: Only set the key if it does not already exist.
|
79
|
+
# - `:xx => true`: Only set the key if it already exist.
|
80
|
+
# - `:keepttl => true`: Retain the time to live associated with the key.
|
81
|
+
# - `:get => true`: Return the old string stored at key, or nil if key did not exist.
|
82
|
+
# @return [String, Boolean] `"OK"` or true, false if `:nx => true` or `:xx => true`
|
83
|
+
def set(key, value, ex: nil, px: nil, exat: nil, pxat: nil, nx: nil, xx: nil, keepttl: nil, get: nil)
|
84
|
+
args = [:set, key, value.to_s]
|
85
|
+
args << "EX" << ex if ex
|
86
|
+
args << "PX" << px if px
|
87
|
+
args << "EXAT" << exat if exat
|
88
|
+
args << "PXAT" << pxat if pxat
|
89
|
+
args << "NX" if nx
|
90
|
+
args << "XX" if xx
|
91
|
+
args << "KEEPTTL" if keepttl
|
92
|
+
args << "GET" if get
|
93
|
+
|
94
|
+
if nx || xx
|
95
|
+
send_command(args, &BoolifySet)
|
96
|
+
else
|
97
|
+
send_command(args)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Set the time to live in seconds of a key.
|
102
|
+
#
|
103
|
+
# @param [String] key
|
104
|
+
# @param [Integer] ttl
|
105
|
+
# @param [String] value
|
106
|
+
# @return [String] `"OK"`
|
107
|
+
def setex(key, ttl, value)
|
108
|
+
send_command([:setex, key, ttl, value.to_s])
|
109
|
+
end
|
110
|
+
|
111
|
+
# Set the time to live in milliseconds of a key.
|
112
|
+
#
|
113
|
+
# @param [String] key
|
114
|
+
# @param [Integer] ttl
|
115
|
+
# @param [String] value
|
116
|
+
# @return [String] `"OK"`
|
117
|
+
def psetex(key, ttl, value)
|
118
|
+
send_command([:psetex, key, ttl, value.to_s])
|
119
|
+
end
|
120
|
+
|
121
|
+
# Set the value of a key, only if the key does not exist.
|
122
|
+
#
|
123
|
+
# @param [String] key
|
124
|
+
# @param [String] value
|
125
|
+
# @return [Boolean] whether the key was set or not
|
126
|
+
def setnx(key, value)
|
127
|
+
send_command([:setnx, key, value.to_s], &Boolify)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Set one or more values.
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# redis.mset("key1", "v1", "key2", "v2")
|
134
|
+
# # => "OK"
|
135
|
+
#
|
136
|
+
# @param [Array<String>] args array of keys and values
|
137
|
+
# @return [String] `"OK"`
|
138
|
+
#
|
139
|
+
# @see #mapped_mset
|
140
|
+
def mset(*args)
|
141
|
+
send_command([:mset] + args)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Set one or more values.
|
145
|
+
#
|
146
|
+
# @example
|
147
|
+
# redis.mapped_mset({ "f1" => "v1", "f2" => "v2" })
|
148
|
+
# # => "OK"
|
149
|
+
#
|
150
|
+
# @param [Hash] hash keys mapping to values
|
151
|
+
# @return [String] `"OK"`
|
152
|
+
#
|
153
|
+
# @see #mset
|
154
|
+
def mapped_mset(hash)
|
155
|
+
mset(hash.to_a.flatten)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Set one or more values, only if none of the keys exist.
|
159
|
+
#
|
160
|
+
# @example
|
161
|
+
# redis.msetnx("key1", "v1", "key2", "v2")
|
162
|
+
# # => true
|
163
|
+
#
|
164
|
+
# @param [Array<String>] args array of keys and values
|
165
|
+
# @return [Boolean] whether or not all values were set
|
166
|
+
#
|
167
|
+
# @see #mapped_msetnx
|
168
|
+
def msetnx(*args)
|
169
|
+
send_command([:msetnx, *args], &Boolify)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Set one or more values, only if none of the keys exist.
|
173
|
+
#
|
174
|
+
# @example
|
175
|
+
# redis.mapped_msetnx({ "key1" => "v1", "key2" => "v2" })
|
176
|
+
# # => true
|
177
|
+
#
|
178
|
+
# @param [Hash] hash keys mapping to values
|
179
|
+
# @return [Boolean] whether or not all values were set
|
180
|
+
#
|
181
|
+
# @see #msetnx
|
182
|
+
def mapped_msetnx(hash)
|
183
|
+
msetnx(hash.to_a.flatten)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Get the value of a key.
|
187
|
+
#
|
188
|
+
# @param [String] key
|
189
|
+
# @return [String]
|
190
|
+
def get(key)
|
191
|
+
send_command([:get, key])
|
192
|
+
end
|
193
|
+
|
194
|
+
# Get the values of all the given keys.
|
195
|
+
#
|
196
|
+
# @example
|
197
|
+
# redis.mget("key1", "key2")
|
198
|
+
# # => ["v1", "v2"]
|
199
|
+
#
|
200
|
+
# @param [Array<String>] keys
|
201
|
+
# @return [Array<String>] an array of values for the specified keys
|
202
|
+
#
|
203
|
+
# @see #mapped_mget
|
204
|
+
def mget(*keys, &blk)
|
205
|
+
send_command([:mget, *keys], &blk)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Get the values of all the given keys.
|
209
|
+
#
|
210
|
+
# @example
|
211
|
+
# redis.mapped_mget("key1", "key2")
|
212
|
+
# # => { "key1" => "v1", "key2" => "v2" }
|
213
|
+
#
|
214
|
+
# @param [Array<String>] keys array of keys
|
215
|
+
# @return [Hash] a hash mapping the specified keys to their values
|
216
|
+
#
|
217
|
+
# @see #mget
|
218
|
+
def mapped_mget(*keys)
|
219
|
+
mget(*keys) do |reply|
|
220
|
+
if reply.is_a?(Array)
|
221
|
+
Hash[keys.zip(reply)]
|
222
|
+
else
|
223
|
+
reply
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Overwrite part of a string at key starting at the specified offset.
|
229
|
+
#
|
230
|
+
# @param [String] key
|
231
|
+
# @param [Integer] offset byte offset
|
232
|
+
# @param [String] value
|
233
|
+
# @return [Integer] length of the string after it was modified
|
234
|
+
def setrange(key, offset, value)
|
235
|
+
send_command([:setrange, key, offset, value.to_s])
|
236
|
+
end
|
237
|
+
|
238
|
+
# Get a substring of the string stored at a key.
|
239
|
+
#
|
240
|
+
# @param [String] key
|
241
|
+
# @param [Integer] start zero-based start offset
|
242
|
+
# @param [Integer] stop zero-based end offset. Use -1 for representing
|
243
|
+
# the end of the string
|
244
|
+
# @return [Integer] `0` or `1`
|
245
|
+
def getrange(key, start, stop)
|
246
|
+
send_command([:getrange, key, start, stop])
|
247
|
+
end
|
248
|
+
|
249
|
+
# Append a value to a key.
|
250
|
+
#
|
251
|
+
# @param [String] key
|
252
|
+
# @param [String] value value to append
|
253
|
+
# @return [Integer] length of the string after appending
|
254
|
+
def append(key, value)
|
255
|
+
send_command([:append, key, value])
|
256
|
+
end
|
257
|
+
|
258
|
+
# Set the string value of a key and return its old value.
|
259
|
+
#
|
260
|
+
# @param [String] key
|
261
|
+
# @param [String] value value to replace the current value with
|
262
|
+
# @return [String] the old value stored in the key, or `nil` if the key
|
263
|
+
# did not exist
|
264
|
+
def getset(key, value)
|
265
|
+
send_command([:getset, key, value.to_s])
|
266
|
+
end
|
267
|
+
|
268
|
+
# Get the value of key and delete the key. This command is similar to GET,
|
269
|
+
# except for the fact that it also deletes the key on success.
|
270
|
+
#
|
271
|
+
# @param [String] key
|
272
|
+
# @return [String] the old value stored in the key, or `nil` if the key
|
273
|
+
# did not exist
|
274
|
+
def getdel(key)
|
275
|
+
send_command([:getdel, key])
|
276
|
+
end
|
277
|
+
|
278
|
+
# Get the value of key and optionally set its expiration. GETEX is similar to
|
279
|
+
# GET, but is a write command with additional options. When no options are
|
280
|
+
# provided, GETEX behaves like GET.
|
281
|
+
#
|
282
|
+
# @param [String] key
|
283
|
+
# @param [Hash] options
|
284
|
+
# - `:ex => Integer`: Set the specified expire time, in seconds.
|
285
|
+
# - `:px => Integer`: Set the specified expire time, in milliseconds.
|
286
|
+
# - `:exat => true`: Set the specified Unix time at which the key will
|
287
|
+
# expire, in seconds.
|
288
|
+
# - `:pxat => true`: Set the specified Unix time at which the key will
|
289
|
+
# expire, in milliseconds.
|
290
|
+
# - `:persist => true`: Remove the time to live associated with the key.
|
291
|
+
# @return [String] The value of key, or nil when key does not exist.
|
292
|
+
def getex(key, ex: nil, px: nil, exat: nil, pxat: nil, persist: false)
|
293
|
+
args = [:getex, key]
|
294
|
+
args << "EX" << ex if ex
|
295
|
+
args << "PX" << px if px
|
296
|
+
args << "EXAT" << exat if exat
|
297
|
+
args << "PXAT" << pxat if pxat
|
298
|
+
args << "PERSIST" if persist
|
299
|
+
|
300
|
+
send_command(args)
|
301
|
+
end
|
302
|
+
|
303
|
+
# Get the length of the value stored in a key.
|
304
|
+
#
|
305
|
+
# @param [String] key
|
306
|
+
# @return [Integer] the length of the value stored in the key, or 0
|
307
|
+
# if the key does not exist
|
308
|
+
def strlen(key)
|
309
|
+
send_command([:strlen, key])
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|