redis-namespace 1.7.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -1
- data/lib/redis/namespace/version.rb +1 -1
- data/lib/redis/namespace.rb +103 -21
- data/spec/deprecation_spec.rb +1 -1
- data/spec/redis_spec.rb +240 -24
- data/spec/spec_helper.rb +4 -0
- metadata +35 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e003f4015162bfd465e79dd90e54b44ae46f0ec269118e10c08215d639166296
|
4
|
+
data.tar.gz: 16078b51e1bdab24977aa2b6fb7d0cd4761a7c41c340fcdacfb96dd32216c061
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb965b575fe3ec2f2f45b99a71839f569f647681939b16576c053ab3e25bf85db1db030941bbe6eaeecc624eeeaf8c0497c58c53c4231440896e9e116bc189e3
|
7
|
+
data.tar.gz: 07b2b2e20c4a152b3e3a4cfbf6abad773f335e098067a9b213e29dd80cfc4519f3d27c43febe6cf8261ffe95e73184e23a1b9ff557007eb7a8308e43a398bbb1
|
data/README.md
CHANGED
@@ -33,6 +33,13 @@ redis_connection.get('ns:foo')
|
|
33
33
|
# => nil
|
34
34
|
```
|
35
35
|
|
36
|
+
Redis::Namespace also supports `Proc` as a namespace and will take the result string as namespace at runtime.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
redis_connection = Redis.new
|
40
|
+
namespaced_redis = Redis::Namespace.new(Proc.new { Tenant.current_tenant }, redis: redis_connection)
|
41
|
+
```
|
42
|
+
|
36
43
|
Installation
|
37
44
|
============
|
38
45
|
|
@@ -79,7 +86,7 @@ namespaced.redis.flushall()
|
|
79
86
|
|
80
87
|
As mentioned above, 2.0 will remove blind passthrough and the administrative command passthrough.
|
81
88
|
By default in 1.5+, deprecation warnings are present and enabled;
|
82
|
-
they can be silenced by initializing `Redis::Namespace` with `
|
89
|
+
they can be silenced by initializing `Redis::Namespace` with `warning: false` or by setting the `REDIS_NAMESPACE_QUIET` environment variable.
|
83
90
|
|
84
91
|
Early opt-in
|
85
92
|
------------
|
data/lib/redis/namespace.rb
CHANGED
@@ -68,12 +68,15 @@ class Redis
|
|
68
68
|
"decrby" => [ :first ],
|
69
69
|
"del" => [ :all ],
|
70
70
|
"dump" => [ :first ],
|
71
|
-
"exists" => [ :
|
71
|
+
"exists" => [ :all ],
|
72
|
+
"exists?" => [ :all ],
|
72
73
|
"expire" => [ :first ],
|
73
74
|
"expireat" => [ :first ],
|
75
|
+
"expiretime" => [ :first ],
|
74
76
|
"eval" => [ :eval_style ],
|
75
77
|
"evalsha" => [ :eval_style ],
|
76
78
|
"get" => [ :first ],
|
79
|
+
"getex" => [ :first ],
|
77
80
|
"getbit" => [ :first ],
|
78
81
|
"getrange" => [ :first ],
|
79
82
|
"getset" => [ :first ],
|
@@ -120,6 +123,7 @@ class Redis
|
|
120
123
|
"persist" => [ :first ],
|
121
124
|
"pexpire" => [ :first ],
|
122
125
|
"pexpireat" => [ :first ],
|
126
|
+
"pexpiretime" => [ :first ],
|
123
127
|
"pfadd" => [ :first ],
|
124
128
|
"pfcount" => [ :all ],
|
125
129
|
"pfmerge" => [ :all ],
|
@@ -136,6 +140,7 @@ class Redis
|
|
136
140
|
"rpush" => [ :first ],
|
137
141
|
"rpushx" => [ :first ],
|
138
142
|
"sadd" => [ :first ],
|
143
|
+
"sadd?" => [ :first ],
|
139
144
|
"scard" => [ :first ],
|
140
145
|
"scan" => [ :scan_style, :second ],
|
141
146
|
"scan_each" => [ :scan_style, :all ],
|
@@ -150,11 +155,13 @@ class Redis
|
|
150
155
|
"sinterstore" => [ :all ],
|
151
156
|
"sismember" => [ :first ],
|
152
157
|
"smembers" => [ :first ],
|
158
|
+
"smismember" => [ :first ],
|
153
159
|
"smove" => [ :exclude_last ],
|
154
160
|
"sort" => [ :sort ],
|
155
161
|
"spop" => [ :first ],
|
156
162
|
"srandmember" => [ :first ],
|
157
163
|
"srem" => [ :first ],
|
164
|
+
"srem?" => [ :first ],
|
158
165
|
"sscan" => [ :first ],
|
159
166
|
"sscan_each" => [ :first ],
|
160
167
|
"strlen" => [ :first ],
|
@@ -199,6 +206,7 @@ class Redis
|
|
199
206
|
HELPER_COMMANDS = {
|
200
207
|
"auth" => [],
|
201
208
|
"disconnect!" => [],
|
209
|
+
"close" => [],
|
202
210
|
"echo" => [],
|
203
211
|
"ping" => [],
|
204
212
|
"time" => [],
|
@@ -235,13 +243,23 @@ class Redis
|
|
235
243
|
# Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
|
236
244
|
Enumerator = Enumerable::Enumerator unless defined?(::Enumerator)
|
237
245
|
|
246
|
+
# This is used by the Redis gem to determine whether or not to display that deprecation message.
|
247
|
+
@sadd_returns_boolean = true
|
248
|
+
|
249
|
+
# This is used by the Redis gem to determine whether or not to display that deprecation message.
|
250
|
+
@srem_returns_boolean = true
|
251
|
+
|
252
|
+
class << self
|
253
|
+
attr_accessor :sadd_returns_boolean, :srem_returns_boolean
|
254
|
+
end
|
255
|
+
|
238
256
|
attr_writer :namespace
|
239
257
|
attr_reader :redis
|
240
258
|
attr_accessor :warning
|
241
259
|
|
242
260
|
def initialize(namespace, options = {})
|
243
261
|
@namespace = namespace
|
244
|
-
@redis = options[:redis] || Redis.
|
262
|
+
@redis = options[:redis] || Redis.new
|
245
263
|
@warning = !!options.fetch(:warning) do
|
246
264
|
!ENV['REDIS_NAMESPACE_QUIET']
|
247
265
|
end
|
@@ -260,7 +278,7 @@ class Redis
|
|
260
278
|
end
|
261
279
|
|
262
280
|
def client
|
263
|
-
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client" +
|
281
|
+
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
|
264
282
|
"method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
|
265
283
|
_client
|
266
284
|
end
|
@@ -306,7 +324,7 @@ class Redis
|
|
306
324
|
:redis => @redis)
|
307
325
|
end
|
308
326
|
|
309
|
-
@namespace
|
327
|
+
@namespace.respond_to?(:call) ? @namespace.call : @namespace
|
310
328
|
end
|
311
329
|
|
312
330
|
def full_namespace
|
@@ -314,7 +332,7 @@ class Redis
|
|
314
332
|
end
|
315
333
|
|
316
334
|
def connection
|
317
|
-
@redis.connection.tap { |info| info[:namespace] =
|
335
|
+
@redis.connection.tap { |info| info[:namespace] = namespace }
|
318
336
|
end
|
319
337
|
|
320
338
|
def exec
|
@@ -324,6 +342,33 @@ class Redis
|
|
324
342
|
def eval(*args)
|
325
343
|
call_with_namespace(:eval, *args)
|
326
344
|
end
|
345
|
+
ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
|
346
|
+
|
347
|
+
# This operation can run for a very long time if the namespace contains lots of keys!
|
348
|
+
# It should be used in tests, or when the namespace is small enough
|
349
|
+
# and you are sure you know what you are doing.
|
350
|
+
def clear
|
351
|
+
if warning?
|
352
|
+
warn("This operation can run for a very long time if the namespace contains lots of keys! " +
|
353
|
+
"It should be used in tests, or when the namespace is small enough " +
|
354
|
+
"and you are sure you know what you are doing.")
|
355
|
+
end
|
356
|
+
|
357
|
+
batch_size = 1000
|
358
|
+
|
359
|
+
if supports_scan?
|
360
|
+
cursor = "0"
|
361
|
+
begin
|
362
|
+
cursor, keys = scan(cursor, count: batch_size)
|
363
|
+
del(*keys) unless keys.empty?
|
364
|
+
end until cursor == "0"
|
365
|
+
else
|
366
|
+
all_keys = keys("*")
|
367
|
+
all_keys.each_slice(batch_size) do |keys|
|
368
|
+
del(*keys)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
327
372
|
|
328
373
|
ADMINISTRATIVE_COMMANDS.keys.each do |command|
|
329
374
|
define_method(command) do |*args, &block|
|
@@ -339,6 +384,7 @@ class Redis
|
|
339
384
|
end
|
340
385
|
call_with_namespace(command, *args, &block)
|
341
386
|
end
|
387
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
342
388
|
end
|
343
389
|
|
344
390
|
COMMANDS.keys.each do |command|
|
@@ -348,6 +394,7 @@ class Redis
|
|
348
394
|
define_method(command) do |*args, &block|
|
349
395
|
call_with_namespace(command, *args, &block)
|
350
396
|
end
|
397
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
351
398
|
end
|
352
399
|
|
353
400
|
def method_missing(command, *args, &block)
|
@@ -365,15 +412,17 @@ class Redis
|
|
365
412
|
"passthrough has been deprecated and will be removed in " +
|
366
413
|
"redis-namespace 2.0 (at #{call_site})")
|
367
414
|
end
|
368
|
-
|
415
|
+
|
416
|
+
wrapped_send(@redis, command, args, &block)
|
369
417
|
else
|
370
418
|
super
|
371
419
|
end
|
372
420
|
end
|
421
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
373
422
|
|
374
423
|
def inspect
|
375
424
|
"<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
|
376
|
-
"for #{@redis.id}/#{
|
425
|
+
"for #{@redis.id}/#{full_namespace}>"
|
377
426
|
end
|
378
427
|
|
379
428
|
def respond_to_missing?(command, include_all=false)
|
@@ -405,6 +454,7 @@ class Redis
|
|
405
454
|
case before
|
406
455
|
when :first
|
407
456
|
args[0] = add_namespace(args[0]) if args[0]
|
457
|
+
args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
|
408
458
|
when :all
|
409
459
|
args = add_namespace(args)
|
410
460
|
when :exclude_first
|
@@ -417,13 +467,14 @@ class Redis
|
|
417
467
|
args.push(last) if last
|
418
468
|
when :exclude_options
|
419
469
|
if args.last.is_a?(Hash)
|
420
|
-
last = args.pop
|
470
|
+
last = ruby2_keywords_hash(args.pop)
|
421
471
|
args = add_namespace(args)
|
422
472
|
args.push(last)
|
423
473
|
else
|
424
474
|
args = add_namespace(args)
|
425
475
|
end
|
426
476
|
when :alternate
|
477
|
+
args = args.flatten
|
427
478
|
args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
|
428
479
|
when :sort
|
429
480
|
args[0] = add_namespace(args[0]) if args[0]
|
@@ -437,6 +488,7 @@ class Redis
|
|
437
488
|
args[1][:get].each_index do |i|
|
438
489
|
args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
|
439
490
|
end
|
491
|
+
args[1] = ruby2_keywords_hash(args[1])
|
440
492
|
end
|
441
493
|
when :eval_style
|
442
494
|
# redis.eval() and evalsha() can either take the form:
|
@@ -457,7 +509,7 @@ class Redis
|
|
457
509
|
when :scan_style
|
458
510
|
options = (args.last.kind_of?(Hash) ? args.pop : {})
|
459
511
|
options[:match] = add_namespace(options.fetch(:match, '*'))
|
460
|
-
args << options
|
512
|
+
args << ruby2_keywords_hash(options)
|
461
513
|
|
462
514
|
if block
|
463
515
|
original_block = block
|
@@ -466,7 +518,7 @@ class Redis
|
|
466
518
|
end
|
467
519
|
|
468
520
|
# Dispatch the command to Redis and store the result.
|
469
|
-
result = @redis
|
521
|
+
result = wrapped_send(@redis, command, args, &block)
|
470
522
|
|
471
523
|
# Don't try to remove namespace from a Redis::Future, you can't.
|
472
524
|
return result if result.is_a?(Redis::Future)
|
@@ -483,9 +535,36 @@ class Redis
|
|
483
535
|
|
484
536
|
result
|
485
537
|
end
|
538
|
+
ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
|
539
|
+
|
540
|
+
protected
|
541
|
+
|
542
|
+
def redis=(redis)
|
543
|
+
@redis = redis
|
544
|
+
end
|
486
545
|
|
487
546
|
private
|
488
547
|
|
548
|
+
if Hash.respond_to?(:ruby2_keywords_hash)
|
549
|
+
def ruby2_keywords_hash(kwargs)
|
550
|
+
Hash.ruby2_keywords_hash(kwargs)
|
551
|
+
end
|
552
|
+
else
|
553
|
+
def ruby2_keywords_hash(kwargs)
|
554
|
+
kwargs
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
def wrapped_send(redis_client, command, args = [], &block)
|
559
|
+
if redis_client.class.name == "ConnectionPool"
|
560
|
+
redis_client.with do |pool_connection|
|
561
|
+
pool_connection.send(command, *args, &block)
|
562
|
+
end
|
563
|
+
else
|
564
|
+
redis_client.send(command, *args, &block)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
489
568
|
# Avoid modifying the caller's (pass-by-reference) arguments.
|
490
569
|
def clone_args(arg)
|
491
570
|
if arg.is_a?(Array)
|
@@ -502,18 +581,16 @@ class Redis
|
|
502
581
|
end
|
503
582
|
|
504
583
|
def namespaced_block(command, &block)
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
@redis = original
|
511
|
-
end
|
584
|
+
if block.arity == 0
|
585
|
+
wrapped_send(redis, command, &block)
|
586
|
+
else
|
587
|
+
outer_block = proc { |r| copy = dup; copy.redis = r; yield copy }
|
588
|
+
wrapped_send(redis, command, &outer_block)
|
512
589
|
end
|
513
590
|
end
|
514
591
|
|
515
592
|
def add_namespace(key)
|
516
|
-
return key unless key &&
|
593
|
+
return key unless key && namespace
|
517
594
|
|
518
595
|
case key
|
519
596
|
when Array
|
@@ -522,12 +599,12 @@ class Redis
|
|
522
599
|
key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
|
523
600
|
key
|
524
601
|
else
|
525
|
-
"#{
|
602
|
+
"#{namespace}:#{key}"
|
526
603
|
end
|
527
604
|
end
|
528
605
|
|
529
606
|
def rem_namespace(key)
|
530
|
-
return key unless key &&
|
607
|
+
return key unless key && namespace
|
531
608
|
|
532
609
|
case key
|
533
610
|
when Array
|
@@ -539,7 +616,7 @@ class Redis
|
|
539
616
|
key.each { |k| yielder.yield rem_namespace(k) }
|
540
617
|
end
|
541
618
|
else
|
542
|
-
key.to_s.sub(/\A#{
|
619
|
+
key.to_s.sub(/\A#{namespace}:/, '')
|
543
620
|
end
|
544
621
|
end
|
545
622
|
|
@@ -554,5 +631,10 @@ class Redis
|
|
554
631
|
Enumerator.new(&block)
|
555
632
|
end
|
556
633
|
end
|
634
|
+
|
635
|
+
def supports_scan?
|
636
|
+
redis_version = @redis.info["redis_version"]
|
637
|
+
Gem::Version.new(redis_version) >= Gem::Version.new("2.8.0")
|
638
|
+
end
|
557
639
|
end
|
558
640
|
end
|
data/spec/deprecation_spec.rb
CHANGED
data/spec/redis_spec.rb
CHANGED
@@ -1,30 +1,20 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/spec_helper'
|
4
|
+
require 'connection_pool'
|
4
5
|
|
5
6
|
describe "redis" do
|
6
|
-
@redis_version = Gem::Version.new(Redis.
|
7
|
+
@redis_version = Gem::Version.new(Redis.new.info["redis_version"])
|
7
8
|
let(:redis_client) { @redis.respond_to?(:_client) ? @redis._client : @redis.client}
|
8
9
|
|
9
|
-
before(:
|
10
|
+
before(:each) do
|
10
11
|
# use database 15 for testing so we dont accidentally step on your real data
|
11
12
|
@redis = Redis.new :db => 15
|
12
|
-
end
|
13
|
-
|
14
|
-
before(:each) do
|
15
|
-
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
|
16
13
|
@redis.flushdb
|
14
|
+
@namespaced = Redis::Namespace.new(:ns, :redis => @redis)
|
17
15
|
@redis.set('foo', 'bar')
|
18
16
|
end
|
19
17
|
|
20
|
-
after(:each) do
|
21
|
-
@redis.flushdb
|
22
|
-
end
|
23
|
-
|
24
|
-
after(:all) do
|
25
|
-
@redis.quit
|
26
|
-
end
|
27
|
-
|
28
18
|
# redis-rb 3.3.4+
|
29
19
|
it "should inject :namespace into connection info" do
|
30
20
|
info = @redis.connection.merge(:namespace => :ns)
|
@@ -52,6 +42,17 @@ describe "redis" do
|
|
52
42
|
expect(@namespaced.type('counter')).to eq('string')
|
53
43
|
end
|
54
44
|
|
45
|
+
it "should work with Proc namespaces" do
|
46
|
+
namespace = Proc.new { :dynamic_ns }
|
47
|
+
namespaced = Redis::Namespace.new(namespace, redis: @redis)
|
48
|
+
|
49
|
+
expect(namespaced.get('foo')).to eq(nil)
|
50
|
+
namespaced.set('foo', 'chris')
|
51
|
+
expect(namespaced.get('foo')).to eq('chris')
|
52
|
+
@redis.set('foo', 'bob')
|
53
|
+
expect(@redis.get('foo')).to eq('bob')
|
54
|
+
end
|
55
|
+
|
55
56
|
context 'when sending capital commands (issue 68)' do
|
56
57
|
it 'should be able to use a namespace' do
|
57
58
|
@namespaced.send('SET', 'fubar', 'quux')
|
@@ -106,6 +107,13 @@ describe "redis" do
|
|
106
107
|
expect(@namespaced.lrange('bar',0,-1)).to eq(['bar'])
|
107
108
|
end
|
108
109
|
|
110
|
+
it "should be able to use a namespace with getex" do
|
111
|
+
expect(@namespaced.set('mykey', 'Hello')).to eq('OK')
|
112
|
+
expect(@namespaced.getex('mykey', ex: 50)).to eq('Hello')
|
113
|
+
expect(@namespaced.get('mykey')).to eq('Hello')
|
114
|
+
expect(@namespaced.ttl('mykey')).to eq(50)
|
115
|
+
end
|
116
|
+
|
109
117
|
it 'should be able to use a namespace with getbit' do
|
110
118
|
@namespaced.set('foo','bar')
|
111
119
|
expect(@namespaced.getbit('foo',1)).to eq(1)
|
@@ -140,10 +148,22 @@ describe "redis" do
|
|
140
148
|
|
141
149
|
it 'should be able to use a namespace with setbit' do
|
142
150
|
@namespaced.setbit('virgin_key', 1, 1)
|
143
|
-
expect(@namespaced.exists('virgin_key')).to be true
|
151
|
+
expect(@namespaced.exists?('virgin_key')).to be true
|
144
152
|
expect(@namespaced.get('virgin_key')).to eq(@namespaced.getrange('virgin_key',0,-1))
|
145
153
|
end
|
146
154
|
|
155
|
+
it 'should be able to use a namespace with exists' do
|
156
|
+
@namespaced.set('foo', 1000)
|
157
|
+
@namespaced.set('bar', 2000)
|
158
|
+
expect(@namespaced.exists('foo', 'bar')).to eq(2)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should be able to use a namespace with exists?' do
|
162
|
+
@namespaced.set('foo', 1000)
|
163
|
+
@namespaced.set('bar', 2000)
|
164
|
+
expect(@namespaced.exists?('does_not_exist', 'bar')).to eq(true)
|
165
|
+
end
|
166
|
+
|
147
167
|
it 'should be able to use a namespace with bitpos' do
|
148
168
|
@namespaced.setbit('bit_map', 42, 1)
|
149
169
|
expect(@namespaced.bitpos('bit_map', 0)).to eq(0)
|
@@ -165,19 +185,44 @@ describe "redis" do
|
|
165
185
|
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({'foo'=>'1000', 'bar'=>'2000', 'baz' => nil})
|
166
186
|
end
|
167
187
|
|
188
|
+
it "should utilize connection_pool while using a namespace with mget" do
|
189
|
+
memo = @namespaced
|
190
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
191
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
192
|
+
|
193
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
194
|
+
expect(arg).to be(an_instance_of(Redis))
|
195
|
+
end.at_least(:once)
|
196
|
+
|
197
|
+
@namespaced.set('foo', 1000)
|
198
|
+
@namespaced.set('bar', 2000)
|
199
|
+
expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
|
200
|
+
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({'foo'=>'1000', 'bar'=>'2000', 'baz' => nil})
|
201
|
+
@redis.get('foo').should eq('bar')
|
202
|
+
|
203
|
+
@namespaced = memo
|
204
|
+
end
|
205
|
+
|
168
206
|
it "should be able to use a namespace with mset" do
|
169
207
|
@namespaced.mset('foo', '1000', 'bar', '2000')
|
170
208
|
expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
|
171
209
|
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil})
|
210
|
+
|
172
211
|
@namespaced.mapped_mset('foo' => '3000', 'bar' => '5000')
|
173
212
|
expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000' })
|
174
213
|
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000', 'baz' => nil})
|
214
|
+
|
215
|
+
@namespaced.mset(['foo', '4000'], ['baz', '6000'])
|
216
|
+
expect(@namespaced.mapped_mget('foo', 'bar', 'baz')).to eq({ 'foo' => '4000', 'bar' => '5000', 'baz' => '6000' })
|
175
217
|
end
|
176
218
|
|
177
219
|
it "should be able to use a namespace with msetnx" do
|
178
220
|
@namespaced.msetnx('foo', '1000', 'bar', '2000')
|
179
221
|
expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' })
|
180
222
|
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil})
|
223
|
+
|
224
|
+
@namespaced.msetnx(['baz', '4000'])
|
225
|
+
expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => '4000'})
|
181
226
|
end
|
182
227
|
|
183
228
|
it "should be able to use a namespace with mapped_msetnx" do
|
@@ -239,7 +284,7 @@ describe "redis" do
|
|
239
284
|
@namespaced.zadd('sort2', 2, 2)
|
240
285
|
@namespaced.zadd('sort2', 3, 3)
|
241
286
|
@namespaced.zadd('sort2', 4, 4)
|
242
|
-
@namespaced.zunionstore('union', ['sort1', 'sort2'], :
|
287
|
+
@namespaced.zunionstore('union', ['sort1', 'sort2'], weights: [2, 1])
|
243
288
|
expect(@namespaced.zrevrange('union', 0, -1)).to eq(%w( 2 4 3 1 ))
|
244
289
|
end
|
245
290
|
|
@@ -313,6 +358,17 @@ describe "redis" do
|
|
313
358
|
expect(values).to match_array(['banana', 'eggplant'])
|
314
359
|
end
|
315
360
|
|
361
|
+
it "should add a new member" do
|
362
|
+
expect(@namespaced.sadd?('foo', 1)).to eq(true)
|
363
|
+
expect(@namespaced.sadd?('foo', 1)).to eq(false)
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should remove members" do
|
367
|
+
@namespaced.sadd('foo', 1)
|
368
|
+
expect(@namespaced.srem?('foo', 1)).to eq(true)
|
369
|
+
expect(@namespaced.srem?('foo', 1)).to eq(false)
|
370
|
+
end
|
371
|
+
|
316
372
|
it "should add namespace to sort" do
|
317
373
|
@namespaced.sadd('foo', 1)
|
318
374
|
@namespaced.sadd('foo', 2)
|
@@ -350,6 +406,26 @@ describe "redis" do
|
|
350
406
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
351
407
|
end
|
352
408
|
|
409
|
+
it "should utilize connection_pool while adding namepsace to multi blocks" do
|
410
|
+
memo = @namespaced
|
411
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
412
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
413
|
+
|
414
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
415
|
+
expect(arg).to be(an_instance_of(Redis))
|
416
|
+
end.at_least(:once)
|
417
|
+
|
418
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
419
|
+
@namespaced.multi do |r|
|
420
|
+
r.del "foo"
|
421
|
+
r.mapped_hmset "foo", {"key1" => "value1"}
|
422
|
+
end
|
423
|
+
expect(@redis.get("foo")).to eq("bar")
|
424
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
425
|
+
|
426
|
+
@namespaced = memo
|
427
|
+
end
|
428
|
+
|
353
429
|
it "should pass through multi commands without block" do
|
354
430
|
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
355
431
|
|
@@ -361,6 +437,28 @@ describe "redis" do
|
|
361
437
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
362
438
|
end
|
363
439
|
|
440
|
+
it "should utilize connection_pool while passing through multi commands without block" do
|
441
|
+
memo = @namespaced
|
442
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
443
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
444
|
+
|
445
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
446
|
+
expect(arg).to be(an_instance_of(Redis))
|
447
|
+
end.at_least(:once)
|
448
|
+
|
449
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
450
|
+
|
451
|
+
@namespaced.multi
|
452
|
+
@namespaced.del "foo"
|
453
|
+
@namespaced.mapped_hmset "foo", {"key1" => "value1"}
|
454
|
+
@namespaced.exec
|
455
|
+
|
456
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
457
|
+
expect(@redis.get("foo")).to eq("bar")
|
458
|
+
|
459
|
+
@namespaced = memo
|
460
|
+
end
|
461
|
+
|
364
462
|
it 'should return futures without attempting to remove namespaces' do
|
365
463
|
@namespaced.multi do
|
366
464
|
@future = @namespaced.keys('*')
|
@@ -377,6 +475,26 @@ describe "redis" do
|
|
377
475
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
378
476
|
end
|
379
477
|
|
478
|
+
it "should utilize connection_pool while adding namespace to pipelined blocks" do
|
479
|
+
memo = @namespaced
|
480
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
481
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
482
|
+
|
483
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
484
|
+
expect(arg).to be(an_instance_of(Redis))
|
485
|
+
end.at_least(:once)
|
486
|
+
|
487
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
488
|
+
@namespaced.pipelined do |r|
|
489
|
+
r.del "foo"
|
490
|
+
r.mapped_hmset "foo", {"key1" => "value1"}
|
491
|
+
end
|
492
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
493
|
+
expect(@redis.get("foo")).to eq("bar")
|
494
|
+
|
495
|
+
@namespaced = memo
|
496
|
+
end
|
497
|
+
|
380
498
|
it "should returned response array from pipelined block" do
|
381
499
|
@namespaced.mset "foo", "bar", "key", "value"
|
382
500
|
result = @namespaced.pipelined do |r|
|
@@ -386,6 +504,27 @@ describe "redis" do
|
|
386
504
|
expect(result).to eq(["bar", "value"])
|
387
505
|
end
|
388
506
|
|
507
|
+
it "is thread safe for multi blocks" do
|
508
|
+
mon = Monitor.new
|
509
|
+
entered = false
|
510
|
+
entered_cond = mon.new_cond
|
511
|
+
|
512
|
+
thread = Thread.new do
|
513
|
+
mon.synchronize do
|
514
|
+
entered_cond.wait_until { entered }
|
515
|
+
@namespaced.multi
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
@namespaced.multi do |transaction|
|
520
|
+
entered = true
|
521
|
+
mon.synchronize { entered_cond.signal }
|
522
|
+
thread.join(0.1)
|
523
|
+
transaction.get("foo")
|
524
|
+
end
|
525
|
+
thread.join
|
526
|
+
end
|
527
|
+
|
389
528
|
it "should add namespace to strlen" do
|
390
529
|
@namespaced.set("mykey", "123456")
|
391
530
|
expect(@namespaced.strlen("mykey")).to eq(6)
|
@@ -442,6 +581,45 @@ describe "redis" do
|
|
442
581
|
expect { @namespaced.unknown('foo') }.to raise_exception NoMethodError
|
443
582
|
end
|
444
583
|
|
584
|
+
describe '#inspect' do
|
585
|
+
let(:single_level_names) { %i[first] }
|
586
|
+
let(:double_level_names) { %i[first second] }
|
587
|
+
let(:triple_level_names) { %i[first second third] }
|
588
|
+
let(:namespace_builder) do
|
589
|
+
->(redis, *namespaces) { namespaces.reduce(redis) { |r, n| Redis::Namespace.new(n, redis: r) } }
|
590
|
+
end
|
591
|
+
let(:regexp_builder) do
|
592
|
+
->(*namespaces) { %r{/#{namespaces.join(':')}>\z} }
|
593
|
+
end
|
594
|
+
|
595
|
+
context 'when one namespace' do
|
596
|
+
let(:single_namespaced) { namespace_builder.call(@redis, *single_level_names) }
|
597
|
+
let(:regexp) { regexp_builder.call(*single_level_names) }
|
598
|
+
|
599
|
+
it 'should have correct ending of inspect string' do
|
600
|
+
expect(regexp =~ single_namespaced.inspect).not_to be(nil)
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context 'when two namespaces' do
|
605
|
+
let(:double_namespaced) { namespace_builder.call(@redis, *double_level_names) }
|
606
|
+
let(:regexp) { regexp_builder.call(*double_level_names) }
|
607
|
+
|
608
|
+
it 'should have correct ending of inspect string' do
|
609
|
+
expect(regexp =~ double_namespaced.inspect).not_to be(nil)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
context 'when three namespaces' do
|
614
|
+
let(:triple_namespaced) { namespace_builder.call(@redis, *triple_level_names) }
|
615
|
+
let(:regexp) { regexp_builder.call(*triple_level_names) }
|
616
|
+
|
617
|
+
it 'should have correct ending of inspect string' do
|
618
|
+
expect(regexp =~ triple_namespaced.inspect).not_to be(nil)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
445
623
|
# Redis 2.6 RC reports its version as 2.5.
|
446
624
|
if @redis_version >= Gem::Version.new("2.5.0")
|
447
625
|
describe "redis 2.6 commands" do
|
@@ -488,6 +666,12 @@ describe "redis" do
|
|
488
666
|
expect(@redis.ttl("ns:foo")).to satisfy {|v| (0..1).include?(v) }
|
489
667
|
end
|
490
668
|
|
669
|
+
it "should namespace expiretime" do
|
670
|
+
@namespaced.set('mykey', 'Hello')
|
671
|
+
@namespaced.expireat('mykey', 2000000000)
|
672
|
+
expect(@namespaced.expiretime('mykey')).to eq(2000000000)
|
673
|
+
end
|
674
|
+
|
491
675
|
it "should namespace hincrbyfloat" do
|
492
676
|
@namespaced.hset('mykey', 'field', 10.50)
|
493
677
|
expect(@namespaced.hincrbyfloat('mykey', 'field', 0.1)).to eq(10.6)
|
@@ -520,6 +704,12 @@ describe "redis" do
|
|
520
704
|
expect(@namespaced.pexpire('mykey', 1555555555005)).to eq(true)
|
521
705
|
end
|
522
706
|
|
707
|
+
it "should namespace pexpiretime" do
|
708
|
+
@namespaced.set('mykey', 'Hello')
|
709
|
+
@namespaced.pexpireat('mykey', 2000000000000)
|
710
|
+
expect(@namespaced.pexpiretime('mykey')).to eq(2000000000000)
|
711
|
+
end
|
712
|
+
|
523
713
|
it "should namespace psetex" do
|
524
714
|
expect(@namespaced.psetex('mykey', 10000, 'Hello')).to eq('OK')
|
525
715
|
expect(@namespaced.get('mykey')).to eq('Hello')
|
@@ -626,7 +816,7 @@ describe "redis" do
|
|
626
816
|
expect(result).to match_array(namespaced_keys)
|
627
817
|
end
|
628
818
|
end
|
629
|
-
end if Redis.
|
819
|
+
end if Redis.new.respond_to?(:scan)
|
630
820
|
|
631
821
|
context '#scan_each' do
|
632
822
|
context 'when :match supplied' do
|
@@ -659,7 +849,7 @@ describe "redis" do
|
|
659
849
|
end
|
660
850
|
end
|
661
851
|
end
|
662
|
-
end if Redis.
|
852
|
+
end if Redis.new.respond_to?(:scan_each)
|
663
853
|
end
|
664
854
|
|
665
855
|
context 'hash scan methods' do
|
@@ -687,7 +877,7 @@ describe "redis" do
|
|
687
877
|
expect(results).to match_array(@redis.hgetall('ns:hsh').to_a)
|
688
878
|
end
|
689
879
|
end
|
690
|
-
end if Redis.
|
880
|
+
end if Redis.new.respond_to?(:hscan)
|
691
881
|
|
692
882
|
context '#hscan_each' do
|
693
883
|
context 'when :match supplied' do
|
@@ -720,7 +910,7 @@ describe "redis" do
|
|
720
910
|
end
|
721
911
|
end
|
722
912
|
end
|
723
|
-
end if Redis.
|
913
|
+
end if Redis.new.respond_to?(:hscan_each)
|
724
914
|
end
|
725
915
|
|
726
916
|
context 'set scan methods' do
|
@@ -748,7 +938,7 @@ describe "redis" do
|
|
748
938
|
expect(results).to match_array(set)
|
749
939
|
end
|
750
940
|
end
|
751
|
-
end if Redis.
|
941
|
+
end if Redis.new.respond_to?(:sscan)
|
752
942
|
|
753
943
|
context '#sscan_each' do
|
754
944
|
context 'when :match supplied' do
|
@@ -781,7 +971,7 @@ describe "redis" do
|
|
781
971
|
end
|
782
972
|
end
|
783
973
|
end
|
784
|
-
end if Redis.
|
974
|
+
end if Redis.new.respond_to?(:sscan_each)
|
785
975
|
end
|
786
976
|
|
787
977
|
context 'zset scan methods' do
|
@@ -811,7 +1001,7 @@ describe "redis" do
|
|
811
1001
|
expect(results).to match_array(hash.to_a)
|
812
1002
|
end
|
813
1003
|
end
|
814
|
-
end if Redis.
|
1004
|
+
end if Redis.new.respond_to?(:zscan)
|
815
1005
|
|
816
1006
|
context '#zscan_each' do
|
817
1007
|
context 'when :match supplied' do
|
@@ -844,7 +1034,7 @@ describe "redis" do
|
|
844
1034
|
end
|
845
1035
|
end
|
846
1036
|
end
|
847
|
-
end if Redis.
|
1037
|
+
end if Redis.new.respond_to?(:zscan_each)
|
848
1038
|
end
|
849
1039
|
end
|
850
1040
|
end
|
@@ -881,4 +1071,30 @@ describe "redis" do
|
|
881
1071
|
expect(sub_sub_namespaced.full_namespace).to eql("ns:sub1:sub2")
|
882
1072
|
end
|
883
1073
|
end
|
1074
|
+
|
1075
|
+
describe :clear do
|
1076
|
+
it "warns with helpful output" do
|
1077
|
+
expect { @namespaced.clear }.to output(/can run for a very long time/).to_stderr
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
it "should delete all the keys" do
|
1081
|
+
@redis.set("foo", "bar")
|
1082
|
+
@namespaced.mset("foo1", "bar", "foo2", "bar")
|
1083
|
+
capture_stderr { @namespaced.clear }
|
1084
|
+
|
1085
|
+
expect(@redis.keys).to eq ["foo"]
|
1086
|
+
expect(@namespaced.keys).to be_empty
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
it "should delete all the keys in older redis" do
|
1090
|
+
allow(@redis).to receive(:info).and_return({ "redis_version" => "2.7.0" })
|
1091
|
+
|
1092
|
+
@redis.set("foo", "bar")
|
1093
|
+
@namespaced.mset("foo1", "bar", "foo2", "bar")
|
1094
|
+
capture_stderr { @namespaced.clear }
|
1095
|
+
|
1096
|
+
expect(@redis.keys).to eq ["foo"]
|
1097
|
+
expect(@namespaced.keys).to be_empty
|
1098
|
+
end
|
1099
|
+
end
|
884
1100
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -12,6 +12,10 @@ $TESTING=true
|
|
12
12
|
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
13
13
|
require 'redis/namespace'
|
14
14
|
|
15
|
+
if Redis.respond_to?(:exists_returns_integer=)
|
16
|
+
Redis.exists_returns_integer = true
|
17
|
+
end
|
18
|
+
|
15
19
|
module Helper
|
16
20
|
def capture_stderr(io = nil)
|
17
21
|
require 'stringio'
|
metadata
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-namespace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Wanstrath
|
8
8
|
- Terence Lee
|
9
9
|
- Steve Klabnik
|
10
10
|
- Ryan Biesemeyer
|
11
|
-
|
11
|
+
- Mike Bianco
|
12
|
+
autorequire:
|
12
13
|
bindir: bin
|
13
14
|
cert_chain: []
|
14
|
-
date:
|
15
|
+
date: 2023-06-08 00:00:00.000000000 Z
|
15
16
|
dependencies:
|
16
17
|
- !ruby/object:Gem::Dependency
|
17
18
|
name: redis
|
@@ -19,28 +20,28 @@ dependencies:
|
|
19
20
|
requirements:
|
20
21
|
- - ">="
|
21
22
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
23
|
+
version: '4'
|
23
24
|
type: :runtime
|
24
25
|
prerelease: false
|
25
26
|
version_requirements: !ruby/object:Gem::Requirement
|
26
27
|
requirements:
|
27
28
|
- - ">="
|
28
29
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
+
version: '4'
|
30
31
|
- !ruby/object:Gem::Dependency
|
31
32
|
name: rake
|
32
33
|
requirement: !ruby/object:Gem::Requirement
|
33
34
|
requirements:
|
34
|
-
- - "
|
35
|
+
- - ">="
|
35
36
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
37
|
+
version: '0'
|
37
38
|
type: :development
|
38
39
|
prerelease: false
|
39
40
|
version_requirements: !ruby/object:Gem::Requirement
|
40
41
|
requirements:
|
41
|
-
- - "
|
42
|
+
- - ">="
|
42
43
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
44
|
+
version: '0'
|
44
45
|
- !ruby/object:Gem::Dependency
|
45
46
|
name: rspec
|
46
47
|
requirement: !ruby/object:Gem::Requirement
|
@@ -69,6 +70,20 @@ dependencies:
|
|
69
70
|
- - ">="
|
70
71
|
- !ruby/object:Gem::Version
|
71
72
|
version: '0'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: connection_pool
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
type: :development
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
72
87
|
description: |
|
73
88
|
Adds a Redis::Namespace class which can be used to namespace calls
|
74
89
|
to Redis. This is useful when using a single instance of Redis with
|
@@ -78,6 +93,7 @@ email:
|
|
78
93
|
- hone02@gmail.com
|
79
94
|
- steve@steveklabnik.com
|
80
95
|
- me@yaauie.com
|
96
|
+
- mike@mikebian.co
|
81
97
|
executables: []
|
82
98
|
extensions: []
|
83
99
|
extra_rdoc_files: []
|
@@ -91,17 +107,21 @@ files:
|
|
91
107
|
- spec/deprecation_spec.rb
|
92
108
|
- spec/redis_spec.rb
|
93
109
|
- spec/spec_helper.rb
|
94
|
-
homepage:
|
110
|
+
homepage: https://github.com/resque/redis-namespace
|
95
111
|
licenses:
|
96
112
|
- MIT
|
97
|
-
metadata:
|
98
|
-
|
113
|
+
metadata:
|
114
|
+
bug_tracker_uri: https://github.com/resque/redis-namespace/issues
|
115
|
+
changelog_uri: https://github.com/resque/redis-namespace/blob/master/CHANGELOG.md
|
116
|
+
documentation_uri: https://www.rubydoc.info/gems/redis-namespace/1.11.0
|
117
|
+
rubygems_mfa_required: 'true'
|
118
|
+
post_install_message:
|
99
119
|
rdoc_options: []
|
100
120
|
require_paths:
|
101
121
|
- lib
|
102
122
|
required_ruby_version: !ruby/object:Gem::Requirement
|
103
123
|
requirements:
|
104
|
-
- - "
|
124
|
+
- - ">="
|
105
125
|
- !ruby/object:Gem::Version
|
106
126
|
version: '2.4'
|
107
127
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -110,8 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
130
|
- !ruby/object:Gem::Version
|
111
131
|
version: '0'
|
112
132
|
requirements: []
|
113
|
-
rubygems_version: 3.
|
114
|
-
signing_key:
|
133
|
+
rubygems_version: 3.4.1
|
134
|
+
signing_key:
|
115
135
|
specification_version: 4
|
116
136
|
summary: Namespaces Redis commands.
|
117
137
|
test_files: []
|