redis-namespace 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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: []
|