redis-namespace 1.7.0 → 1.10.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 +97 -21
- data/spec/deprecation_spec.rb +1 -1
- data/spec/redis_spec.rb +222 -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: 8c4fe7070f484a694ce41f97a0297e03d92cfa67746903d9fb74fa8439410494
|
4
|
+
data.tar.gz: 0cbfe04c2ca7b2d42ee603f0d67ba21c13cb938832cc99f89a2323842bb828a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec085b7e9fba5241cb2e2ad4ccf22d4282001a0ee37731e408a2135ea5e5439747441046cc6c48a2a372afe99f2fb6a67401867a20c8605e41206954eca72078
|
7
|
+
data.tar.gz: 0eff5c268bba88cb8bd5e0ab8115a404fed3180e82ebc4297ab8675da6c73e13b3bb943e77ec0392de4460683488589bbc227d95515aa5dc70cdb4236b58801d
|
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,14 @@ 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 ],
|
74
75
|
"eval" => [ :eval_style ],
|
75
76
|
"evalsha" => [ :eval_style ],
|
76
77
|
"get" => [ :first ],
|
78
|
+
"getex" => [ :first ],
|
77
79
|
"getbit" => [ :first ],
|
78
80
|
"getrange" => [ :first ],
|
79
81
|
"getset" => [ :first ],
|
@@ -136,6 +138,7 @@ class Redis
|
|
136
138
|
"rpush" => [ :first ],
|
137
139
|
"rpushx" => [ :first ],
|
138
140
|
"sadd" => [ :first ],
|
141
|
+
"sadd?" => [ :first ],
|
139
142
|
"scard" => [ :first ],
|
140
143
|
"scan" => [ :scan_style, :second ],
|
141
144
|
"scan_each" => [ :scan_style, :all ],
|
@@ -150,6 +153,7 @@ class Redis
|
|
150
153
|
"sinterstore" => [ :all ],
|
151
154
|
"sismember" => [ :first ],
|
152
155
|
"smembers" => [ :first ],
|
156
|
+
"smismember" => [ :first ],
|
153
157
|
"smove" => [ :exclude_last ],
|
154
158
|
"sort" => [ :sort ],
|
155
159
|
"spop" => [ :first ],
|
@@ -199,6 +203,7 @@ class Redis
|
|
199
203
|
HELPER_COMMANDS = {
|
200
204
|
"auth" => [],
|
201
205
|
"disconnect!" => [],
|
206
|
+
"close" => [],
|
202
207
|
"echo" => [],
|
203
208
|
"ping" => [],
|
204
209
|
"time" => [],
|
@@ -235,13 +240,20 @@ class Redis
|
|
235
240
|
# Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
|
236
241
|
Enumerator = Enumerable::Enumerator unless defined?(::Enumerator)
|
237
242
|
|
243
|
+
# This is used by the Redis gem to determine whether or not to display that deprecation message.
|
244
|
+
@sadd_returns_boolean = true
|
245
|
+
|
246
|
+
class << self
|
247
|
+
attr_accessor :sadd_returns_boolean
|
248
|
+
end
|
249
|
+
|
238
250
|
attr_writer :namespace
|
239
251
|
attr_reader :redis
|
240
252
|
attr_accessor :warning
|
241
253
|
|
242
254
|
def initialize(namespace, options = {})
|
243
255
|
@namespace = namespace
|
244
|
-
@redis = options[:redis] || Redis.
|
256
|
+
@redis = options[:redis] || Redis.new
|
245
257
|
@warning = !!options.fetch(:warning) do
|
246
258
|
!ENV['REDIS_NAMESPACE_QUIET']
|
247
259
|
end
|
@@ -260,7 +272,7 @@ class Redis
|
|
260
272
|
end
|
261
273
|
|
262
274
|
def client
|
263
|
-
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client" +
|
275
|
+
warn("The client method is deprecated as of redis-rb 4.0.0, please use the new _client " +
|
264
276
|
"method instead. Support for the old method will be removed in redis-namespace 2.0.") if @has_new_client_method && deprecations?
|
265
277
|
_client
|
266
278
|
end
|
@@ -306,7 +318,7 @@ class Redis
|
|
306
318
|
:redis => @redis)
|
307
319
|
end
|
308
320
|
|
309
|
-
@namespace
|
321
|
+
@namespace.respond_to?(:call) ? @namespace.call : @namespace
|
310
322
|
end
|
311
323
|
|
312
324
|
def full_namespace
|
@@ -314,7 +326,7 @@ class Redis
|
|
314
326
|
end
|
315
327
|
|
316
328
|
def connection
|
317
|
-
@redis.connection.tap { |info| info[:namespace] =
|
329
|
+
@redis.connection.tap { |info| info[:namespace] = namespace }
|
318
330
|
end
|
319
331
|
|
320
332
|
def exec
|
@@ -324,6 +336,33 @@ class Redis
|
|
324
336
|
def eval(*args)
|
325
337
|
call_with_namespace(:eval, *args)
|
326
338
|
end
|
339
|
+
ruby2_keywords(:eval) if respond_to?(:ruby2_keywords, true)
|
340
|
+
|
341
|
+
# This operation can run for a very long time if the namespace contains lots of keys!
|
342
|
+
# It should be used in tests, or when the namespace is small enough
|
343
|
+
# and you are sure you know what you are doing.
|
344
|
+
def clear
|
345
|
+
if warning?
|
346
|
+
warn("This operation can run for a very long time if the namespace contains lots of keys! " +
|
347
|
+
"It should be used in tests, or when the namespace is small enough " +
|
348
|
+
"and you are sure you know what you are doing.")
|
349
|
+
end
|
350
|
+
|
351
|
+
batch_size = 1000
|
352
|
+
|
353
|
+
if supports_scan?
|
354
|
+
cursor = "0"
|
355
|
+
begin
|
356
|
+
cursor, keys = scan(cursor, count: batch_size)
|
357
|
+
del(*keys) unless keys.empty?
|
358
|
+
end until cursor == "0"
|
359
|
+
else
|
360
|
+
all_keys = keys("*")
|
361
|
+
all_keys.each_slice(batch_size) do |keys|
|
362
|
+
del(*keys)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
327
366
|
|
328
367
|
ADMINISTRATIVE_COMMANDS.keys.each do |command|
|
329
368
|
define_method(command) do |*args, &block|
|
@@ -339,6 +378,7 @@ class Redis
|
|
339
378
|
end
|
340
379
|
call_with_namespace(command, *args, &block)
|
341
380
|
end
|
381
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
342
382
|
end
|
343
383
|
|
344
384
|
COMMANDS.keys.each do |command|
|
@@ -348,6 +388,7 @@ class Redis
|
|
348
388
|
define_method(command) do |*args, &block|
|
349
389
|
call_with_namespace(command, *args, &block)
|
350
390
|
end
|
391
|
+
ruby2_keywords(command) if respond_to?(:ruby2_keywords, true)
|
351
392
|
end
|
352
393
|
|
353
394
|
def method_missing(command, *args, &block)
|
@@ -365,15 +406,17 @@ class Redis
|
|
365
406
|
"passthrough has been deprecated and will be removed in " +
|
366
407
|
"redis-namespace 2.0 (at #{call_site})")
|
367
408
|
end
|
368
|
-
|
409
|
+
|
410
|
+
wrapped_send(@redis, command, args, &block)
|
369
411
|
else
|
370
412
|
super
|
371
413
|
end
|
372
414
|
end
|
415
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
373
416
|
|
374
417
|
def inspect
|
375
418
|
"<#{self.class.name} v#{VERSION} with client v#{Redis::VERSION} "\
|
376
|
-
"for #{@redis.id}/#{
|
419
|
+
"for #{@redis.id}/#{full_namespace}>"
|
377
420
|
end
|
378
421
|
|
379
422
|
def respond_to_missing?(command, include_all=false)
|
@@ -405,6 +448,7 @@ class Redis
|
|
405
448
|
case before
|
406
449
|
when :first
|
407
450
|
args[0] = add_namespace(args[0]) if args[0]
|
451
|
+
args[-1] = ruby2_keywords_hash(args[-1]) if args[-1].is_a?(Hash)
|
408
452
|
when :all
|
409
453
|
args = add_namespace(args)
|
410
454
|
when :exclude_first
|
@@ -417,13 +461,14 @@ class Redis
|
|
417
461
|
args.push(last) if last
|
418
462
|
when :exclude_options
|
419
463
|
if args.last.is_a?(Hash)
|
420
|
-
last = args.pop
|
464
|
+
last = ruby2_keywords_hash(args.pop)
|
421
465
|
args = add_namespace(args)
|
422
466
|
args.push(last)
|
423
467
|
else
|
424
468
|
args = add_namespace(args)
|
425
469
|
end
|
426
470
|
when :alternate
|
471
|
+
args = args.flatten
|
427
472
|
args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? }
|
428
473
|
when :sort
|
429
474
|
args[0] = add_namespace(args[0]) if args[0]
|
@@ -437,6 +482,7 @@ class Redis
|
|
437
482
|
args[1][:get].each_index do |i|
|
438
483
|
args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#"
|
439
484
|
end
|
485
|
+
args[1] = ruby2_keywords_hash(args[1])
|
440
486
|
end
|
441
487
|
when :eval_style
|
442
488
|
# redis.eval() and evalsha() can either take the form:
|
@@ -457,7 +503,7 @@ class Redis
|
|
457
503
|
when :scan_style
|
458
504
|
options = (args.last.kind_of?(Hash) ? args.pop : {})
|
459
505
|
options[:match] = add_namespace(options.fetch(:match, '*'))
|
460
|
-
args << options
|
506
|
+
args << ruby2_keywords_hash(options)
|
461
507
|
|
462
508
|
if block
|
463
509
|
original_block = block
|
@@ -466,7 +512,7 @@ class Redis
|
|
466
512
|
end
|
467
513
|
|
468
514
|
# Dispatch the command to Redis and store the result.
|
469
|
-
result = @redis
|
515
|
+
result = wrapped_send(@redis, command, args, &block)
|
470
516
|
|
471
517
|
# Don't try to remove namespace from a Redis::Future, you can't.
|
472
518
|
return result if result.is_a?(Redis::Future)
|
@@ -483,9 +529,36 @@ class Redis
|
|
483
529
|
|
484
530
|
result
|
485
531
|
end
|
532
|
+
ruby2_keywords(:call_with_namespace) if respond_to?(:ruby2_keywords, true)
|
533
|
+
|
534
|
+
protected
|
535
|
+
|
536
|
+
def redis=(redis)
|
537
|
+
@redis = redis
|
538
|
+
end
|
486
539
|
|
487
540
|
private
|
488
541
|
|
542
|
+
if Hash.respond_to?(:ruby2_keywords_hash)
|
543
|
+
def ruby2_keywords_hash(kwargs)
|
544
|
+
Hash.ruby2_keywords_hash(kwargs)
|
545
|
+
end
|
546
|
+
else
|
547
|
+
def ruby2_keywords_hash(kwargs)
|
548
|
+
kwargs
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
def wrapped_send(redis_client, command, args = [], &block)
|
553
|
+
if redis_client.class.name == "ConnectionPool"
|
554
|
+
redis_client.with do |pool_connection|
|
555
|
+
pool_connection.send(command, *args, &block)
|
556
|
+
end
|
557
|
+
else
|
558
|
+
redis_client.send(command, *args, &block)
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
489
562
|
# Avoid modifying the caller's (pass-by-reference) arguments.
|
490
563
|
def clone_args(arg)
|
491
564
|
if arg.is_a?(Array)
|
@@ -502,18 +575,16 @@ class Redis
|
|
502
575
|
end
|
503
576
|
|
504
577
|
def namespaced_block(command, &block)
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
@redis = original
|
511
|
-
end
|
578
|
+
if block.arity == 0
|
579
|
+
wrapped_send(redis, command, &block)
|
580
|
+
else
|
581
|
+
outer_block = proc { |r| copy = dup; copy.redis = r; yield copy }
|
582
|
+
wrapped_send(redis, command, &outer_block)
|
512
583
|
end
|
513
584
|
end
|
514
585
|
|
515
586
|
def add_namespace(key)
|
516
|
-
return key unless key &&
|
587
|
+
return key unless key && namespace
|
517
588
|
|
518
589
|
case key
|
519
590
|
when Array
|
@@ -522,12 +593,12 @@ class Redis
|
|
522
593
|
key.keys.each {|k| key[add_namespace(k)] = key.delete(k)}
|
523
594
|
key
|
524
595
|
else
|
525
|
-
"#{
|
596
|
+
"#{namespace}:#{key}"
|
526
597
|
end
|
527
598
|
end
|
528
599
|
|
529
600
|
def rem_namespace(key)
|
530
|
-
return key unless key &&
|
601
|
+
return key unless key && namespace
|
531
602
|
|
532
603
|
case key
|
533
604
|
when Array
|
@@ -539,7 +610,7 @@ class Redis
|
|
539
610
|
key.each { |k| yielder.yield rem_namespace(k) }
|
540
611
|
end
|
541
612
|
else
|
542
|
-
key.to_s.sub(/\A#{
|
613
|
+
key.to_s.sub(/\A#{namespace}:/, '')
|
543
614
|
end
|
544
615
|
end
|
545
616
|
|
@@ -554,5 +625,10 @@ class Redis
|
|
554
625
|
Enumerator.new(&block)
|
555
626
|
end
|
556
627
|
end
|
628
|
+
|
629
|
+
def supports_scan?
|
630
|
+
redis_version = @redis.info["redis_version"]
|
631
|
+
Gem::Version.new(redis_version) >= Gem::Version.new("2.8.0")
|
632
|
+
end
|
557
633
|
end
|
558
634
|
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,11 @@ 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
|
+
|
316
366
|
it "should add namespace to sort" do
|
317
367
|
@namespaced.sadd('foo', 1)
|
318
368
|
@namespaced.sadd('foo', 2)
|
@@ -350,6 +400,26 @@ describe "redis" do
|
|
350
400
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
351
401
|
end
|
352
402
|
|
403
|
+
it "should utilize connection_pool while adding namepsace to multi blocks" do
|
404
|
+
memo = @namespaced
|
405
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
406
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
407
|
+
|
408
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
409
|
+
expect(arg).to be(an_instance_of(Redis))
|
410
|
+
end.at_least(:once)
|
411
|
+
|
412
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
413
|
+
@namespaced.multi do |r|
|
414
|
+
r.del "foo"
|
415
|
+
r.mapped_hmset "foo", {"key1" => "value1"}
|
416
|
+
end
|
417
|
+
expect(@redis.get("foo")).to eq("bar")
|
418
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
419
|
+
|
420
|
+
@namespaced = memo
|
421
|
+
end
|
422
|
+
|
353
423
|
it "should pass through multi commands without block" do
|
354
424
|
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
355
425
|
|
@@ -361,6 +431,28 @@ describe "redis" do
|
|
361
431
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
362
432
|
end
|
363
433
|
|
434
|
+
it "should utilize connection_pool while passing through multi commands without block" do
|
435
|
+
memo = @namespaced
|
436
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
437
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
438
|
+
|
439
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
440
|
+
expect(arg).to be(an_instance_of(Redis))
|
441
|
+
end.at_least(:once)
|
442
|
+
|
443
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
444
|
+
|
445
|
+
@namespaced.multi
|
446
|
+
@namespaced.del "foo"
|
447
|
+
@namespaced.mapped_hmset "foo", {"key1" => "value1"}
|
448
|
+
@namespaced.exec
|
449
|
+
|
450
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
451
|
+
expect(@redis.get("foo")).to eq("bar")
|
452
|
+
|
453
|
+
@namespaced = memo
|
454
|
+
end
|
455
|
+
|
364
456
|
it 'should return futures without attempting to remove namespaces' do
|
365
457
|
@namespaced.multi do
|
366
458
|
@future = @namespaced.keys('*')
|
@@ -377,6 +469,26 @@ describe "redis" do
|
|
377
469
|
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
378
470
|
end
|
379
471
|
|
472
|
+
it "should utilize connection_pool while adding namespace to pipelined blocks" do
|
473
|
+
memo = @namespaced
|
474
|
+
connection_pool = ConnectionPool.new(size: 2, timeout: 2) { Redis.new db: 15 }
|
475
|
+
@namespaced = Redis::Namespace.new(:ns, redis: connection_pool)
|
476
|
+
|
477
|
+
expect(connection_pool).to receive(:with).and_call_original do |arg|
|
478
|
+
expect(arg).to be(an_instance_of(Redis))
|
479
|
+
end.at_least(:once)
|
480
|
+
|
481
|
+
@namespaced.mapped_hmset "foo", {"key" => "value"}
|
482
|
+
@namespaced.pipelined do |r|
|
483
|
+
r.del "foo"
|
484
|
+
r.mapped_hmset "foo", {"key1" => "value1"}
|
485
|
+
end
|
486
|
+
expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"})
|
487
|
+
expect(@redis.get("foo")).to eq("bar")
|
488
|
+
|
489
|
+
@namespaced = memo
|
490
|
+
end
|
491
|
+
|
380
492
|
it "should returned response array from pipelined block" do
|
381
493
|
@namespaced.mset "foo", "bar", "key", "value"
|
382
494
|
result = @namespaced.pipelined do |r|
|
@@ -386,6 +498,27 @@ describe "redis" do
|
|
386
498
|
expect(result).to eq(["bar", "value"])
|
387
499
|
end
|
388
500
|
|
501
|
+
it "is thread safe for multi blocks" do
|
502
|
+
mon = Monitor.new
|
503
|
+
entered = false
|
504
|
+
entered_cond = mon.new_cond
|
505
|
+
|
506
|
+
thread = Thread.new do
|
507
|
+
mon.synchronize do
|
508
|
+
entered_cond.wait_until { entered }
|
509
|
+
@namespaced.multi
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
@namespaced.multi do |transaction|
|
514
|
+
entered = true
|
515
|
+
mon.synchronize { entered_cond.signal }
|
516
|
+
thread.join(0.1)
|
517
|
+
transaction.get("foo")
|
518
|
+
end
|
519
|
+
thread.join
|
520
|
+
end
|
521
|
+
|
389
522
|
it "should add namespace to strlen" do
|
390
523
|
@namespaced.set("mykey", "123456")
|
391
524
|
expect(@namespaced.strlen("mykey")).to eq(6)
|
@@ -442,6 +575,45 @@ describe "redis" do
|
|
442
575
|
expect { @namespaced.unknown('foo') }.to raise_exception NoMethodError
|
443
576
|
end
|
444
577
|
|
578
|
+
describe '#inspect' do
|
579
|
+
let(:single_level_names) { %i[first] }
|
580
|
+
let(:double_level_names) { %i[first second] }
|
581
|
+
let(:triple_level_names) { %i[first second third] }
|
582
|
+
let(:namespace_builder) do
|
583
|
+
->(redis, *namespaces) { namespaces.reduce(redis) { |r, n| Redis::Namespace.new(n, redis: r) } }
|
584
|
+
end
|
585
|
+
let(:regexp_builder) do
|
586
|
+
->(*namespaces) { %r{/#{namespaces.join(':')}>\z} }
|
587
|
+
end
|
588
|
+
|
589
|
+
context 'when one namespace' do
|
590
|
+
let(:single_namespaced) { namespace_builder.call(@redis, *single_level_names) }
|
591
|
+
let(:regexp) { regexp_builder.call(*single_level_names) }
|
592
|
+
|
593
|
+
it 'should have correct ending of inspect string' do
|
594
|
+
expect(regexp =~ single_namespaced.inspect).not_to be(nil)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
context 'when two namespaces' do
|
599
|
+
let(:double_namespaced) { namespace_builder.call(@redis, *double_level_names) }
|
600
|
+
let(:regexp) { regexp_builder.call(*double_level_names) }
|
601
|
+
|
602
|
+
it 'should have correct ending of inspect string' do
|
603
|
+
expect(regexp =~ double_namespaced.inspect).not_to be(nil)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
context 'when three namespaces' do
|
608
|
+
let(:triple_namespaced) { namespace_builder.call(@redis, *triple_level_names) }
|
609
|
+
let(:regexp) { regexp_builder.call(*triple_level_names) }
|
610
|
+
|
611
|
+
it 'should have correct ending of inspect string' do
|
612
|
+
expect(regexp =~ triple_namespaced.inspect).not_to be(nil)
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
445
617
|
# Redis 2.6 RC reports its version as 2.5.
|
446
618
|
if @redis_version >= Gem::Version.new("2.5.0")
|
447
619
|
describe "redis 2.6 commands" do
|
@@ -626,7 +798,7 @@ describe "redis" do
|
|
626
798
|
expect(result).to match_array(namespaced_keys)
|
627
799
|
end
|
628
800
|
end
|
629
|
-
end if Redis.
|
801
|
+
end if Redis.new.respond_to?(:scan)
|
630
802
|
|
631
803
|
context '#scan_each' do
|
632
804
|
context 'when :match supplied' do
|
@@ -659,7 +831,7 @@ describe "redis" do
|
|
659
831
|
end
|
660
832
|
end
|
661
833
|
end
|
662
|
-
end if Redis.
|
834
|
+
end if Redis.new.respond_to?(:scan_each)
|
663
835
|
end
|
664
836
|
|
665
837
|
context 'hash scan methods' do
|
@@ -687,7 +859,7 @@ describe "redis" do
|
|
687
859
|
expect(results).to match_array(@redis.hgetall('ns:hsh').to_a)
|
688
860
|
end
|
689
861
|
end
|
690
|
-
end if Redis.
|
862
|
+
end if Redis.new.respond_to?(:hscan)
|
691
863
|
|
692
864
|
context '#hscan_each' do
|
693
865
|
context 'when :match supplied' do
|
@@ -720,7 +892,7 @@ describe "redis" do
|
|
720
892
|
end
|
721
893
|
end
|
722
894
|
end
|
723
|
-
end if Redis.
|
895
|
+
end if Redis.new.respond_to?(:hscan_each)
|
724
896
|
end
|
725
897
|
|
726
898
|
context 'set scan methods' do
|
@@ -748,7 +920,7 @@ describe "redis" do
|
|
748
920
|
expect(results).to match_array(set)
|
749
921
|
end
|
750
922
|
end
|
751
|
-
end if Redis.
|
923
|
+
end if Redis.new.respond_to?(:sscan)
|
752
924
|
|
753
925
|
context '#sscan_each' do
|
754
926
|
context 'when :match supplied' do
|
@@ -781,7 +953,7 @@ describe "redis" do
|
|
781
953
|
end
|
782
954
|
end
|
783
955
|
end
|
784
|
-
end if Redis.
|
956
|
+
end if Redis.new.respond_to?(:sscan_each)
|
785
957
|
end
|
786
958
|
|
787
959
|
context 'zset scan methods' do
|
@@ -811,7 +983,7 @@ describe "redis" do
|
|
811
983
|
expect(results).to match_array(hash.to_a)
|
812
984
|
end
|
813
985
|
end
|
814
|
-
end if Redis.
|
986
|
+
end if Redis.new.respond_to?(:zscan)
|
815
987
|
|
816
988
|
context '#zscan_each' do
|
817
989
|
context 'when :match supplied' do
|
@@ -844,7 +1016,7 @@ describe "redis" do
|
|
844
1016
|
end
|
845
1017
|
end
|
846
1018
|
end
|
847
|
-
end if Redis.
|
1019
|
+
end if Redis.new.respond_to?(:zscan_each)
|
848
1020
|
end
|
849
1021
|
end
|
850
1022
|
end
|
@@ -881,4 +1053,30 @@ describe "redis" do
|
|
881
1053
|
expect(sub_sub_namespaced.full_namespace).to eql("ns:sub1:sub2")
|
882
1054
|
end
|
883
1055
|
end
|
1056
|
+
|
1057
|
+
describe :clear do
|
1058
|
+
it "warns with helpful output" do
|
1059
|
+
expect { @namespaced.clear }.to output(/can run for a very long time/).to_stderr
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
it "should delete all the keys" do
|
1063
|
+
@redis.set("foo", "bar")
|
1064
|
+
@namespaced.mset("foo1", "bar", "foo2", "bar")
|
1065
|
+
capture_stderr { @namespaced.clear }
|
1066
|
+
|
1067
|
+
expect(@redis.keys).to eq ["foo"]
|
1068
|
+
expect(@namespaced.keys).to be_empty
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it "should delete all the keys in older redis" do
|
1072
|
+
allow(@redis).to receive(:info).and_return({ "redis_version" => "2.7.0" })
|
1073
|
+
|
1074
|
+
@redis.set("foo", "bar")
|
1075
|
+
@namespaced.mset("foo1", "bar", "foo2", "bar")
|
1076
|
+
capture_stderr { @namespaced.clear }
|
1077
|
+
|
1078
|
+
expect(@redis.keys).to eq ["foo"]
|
1079
|
+
expect(@namespaced.keys).to be_empty
|
1080
|
+
end
|
1081
|
+
end
|
884
1082
|
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.10.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: 2022-12-20 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.10.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.3.15
|
134
|
+
signing_key:
|
115
135
|
specification_version: 4
|
116
136
|
summary: Namespaces Redis commands.
|
117
137
|
test_files: []
|