redis-namespace 1.7.0 → 1.11.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 +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: []
|