rediska 0.0.2
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.
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +70 -0
- data/LICENSE +20 -0
- data/README.md +95 -0
- data/Rakefile +7 -0
- data/lib/rediska/configuration.rb +11 -0
- data/lib/rediska/connection.rb +67 -0
- data/lib/rediska/databases/expiring.rb +87 -0
- data/lib/rediska/databases/memory.rb +21 -0
- data/lib/rediska/databases/pstore.rb +72 -0
- data/lib/rediska/driver.rb +910 -0
- data/lib/rediska/sorted_set_argument_handler.rb +54 -0
- data/lib/rediska/sorted_set_store.rb +80 -0
- data/lib/rediska/version.rb +3 -0
- data/lib/rediska/zset.rb +26 -0
- data/lib/rediska.rb +18 -0
- data/rediska.gemspec +26 -0
- data/spec/redis_spec.rb +64 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/compatibility.rb +7 -0
- data/spec/support/connection.rb +65 -0
- data/spec/support/hashes.rb +189 -0
- data/spec/support/keys.rb +261 -0
- data/spec/support/lists.rb +196 -0
- data/spec/support/server.rb +93 -0
- data/spec/support/sets.rb +175 -0
- data/spec/support/sorted_sets.rb +447 -0
- data/spec/support/strings.rb +240 -0
- data/spec/support/transactions.rb +11 -0
- data/spec/support/upcase_method_names.rb +9 -0
- metadata +174 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
module Rediska
|
2
|
+
class SortedSetArgumentHandler
|
3
|
+
attr_reader :aggregate
|
4
|
+
attr_accessor :number_of_keys, :keys, :weights, :type
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
@number_of_keys = args.shift
|
8
|
+
@keys = args.shift(number_of_keys)
|
9
|
+
args.inject(self) {|handler, item| handler.handle(item) }
|
10
|
+
|
11
|
+
# Defaults.
|
12
|
+
@weights ||= Array.new(number_of_keys) { 1 }
|
13
|
+
@aggregate ||= :sum
|
14
|
+
|
15
|
+
# Validation.
|
16
|
+
raise Redis::CommandError, 'ERR syntax error' unless weights.size == number_of_keys
|
17
|
+
raise Redis::CommandError, 'ERR syntax error' unless [:min, :max, :sum].include?(aggregate)
|
18
|
+
end
|
19
|
+
|
20
|
+
def aggregate=(str)
|
21
|
+
raise Redis::CommandError, 'ERR syntax error' if @aggregate
|
22
|
+
|
23
|
+
@aggregate = str.to_s.downcase.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle(item)
|
27
|
+
case item
|
28
|
+
when 'WEIGHTS'
|
29
|
+
@type = :weights
|
30
|
+
@weights = []
|
31
|
+
when 'AGGREGATE'
|
32
|
+
@type = :aggregate
|
33
|
+
when nil
|
34
|
+
raise Redis::CommandError, 'ERR syntax error'
|
35
|
+
else
|
36
|
+
send "handle_#{type}", item
|
37
|
+
end
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_weights(item)
|
43
|
+
@weights << item
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_aggregate(item)
|
47
|
+
@aggregate = item
|
48
|
+
end
|
49
|
+
|
50
|
+
def inject_block
|
51
|
+
lambda { |handler, item| handler.handle(item) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Rediska
|
2
|
+
class SortedSetStore
|
3
|
+
attr_accessor :data, :weights, :aggregate, :keys
|
4
|
+
|
5
|
+
def initialize(params, data)
|
6
|
+
@data = data
|
7
|
+
@weights = params.weights
|
8
|
+
@aggregate = params.aggregate
|
9
|
+
@keys = params.keys
|
10
|
+
end
|
11
|
+
|
12
|
+
def hashes
|
13
|
+
@hashes ||= keys.map do |src|
|
14
|
+
case data[src]
|
15
|
+
when ::Set
|
16
|
+
Hash[data[src].map {|k,v| [k, 1]}]
|
17
|
+
when Hash
|
18
|
+
data[src]
|
19
|
+
else
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def computed_values
|
26
|
+
@computed_values ||= begin
|
27
|
+
# Do nothing if all weights are 1, as n * 1 is n.
|
28
|
+
if weights.all? {|weight| weight == 1 }
|
29
|
+
values = hashes
|
30
|
+
# Otherwise, multiply the values in each hash by that hash's weighting
|
31
|
+
else
|
32
|
+
values = hashes.each_with_index.map do |hash, index|
|
33
|
+
weight = weights[index]
|
34
|
+
Hash[hash.map {|k, v| [k, (v * weight)]}]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def aggregate_sum(out)
|
41
|
+
selected_keys.each do |key|
|
42
|
+
out[key] = computed_values.inject(0) do |n, hash|
|
43
|
+
n + (hash[key] || 0)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def aggregate_min(out)
|
49
|
+
selected_keys.each do |key|
|
50
|
+
out[key] = computed_values.map {|h| h[key] }.compact.min
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def aggregate_max(out)
|
55
|
+
selected_keys.each do |key|
|
56
|
+
out[key] = computed_values.map {|h| h[key] }.compact.max
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def selected_keys
|
61
|
+
raise NotImplemented, "subclass needs to implement #selected_keys"
|
62
|
+
end
|
63
|
+
|
64
|
+
def call
|
65
|
+
ZSet.new.tap {|out| send("aggregate_#{aggregate}", out) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class SortedSetIntersectStore < SortedSetStore
|
70
|
+
def selected_keys
|
71
|
+
@values ||= hashes.inject([]) { |r, h| r.empty? ? h.keys : (r & h.keys) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class SortedSetUnionStore < SortedSetStore
|
76
|
+
def selected_keys
|
77
|
+
@values ||= hashes.map(&:keys).flatten.uniq
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/rediska/zset.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rediska
|
2
|
+
class ZSet < Hash
|
3
|
+
def []=(key, val)
|
4
|
+
super(key, floatify(val))
|
5
|
+
end
|
6
|
+
|
7
|
+
def increment(key, val)
|
8
|
+
self[key] += floatify(val)
|
9
|
+
end
|
10
|
+
|
11
|
+
def select_by_score(min, max)
|
12
|
+
min = floatify(min)
|
13
|
+
max = floatify(max)
|
14
|
+
reject {|_,v| v < min || v > max }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def floatify(str)
|
19
|
+
if inf = str.to_s.match(/^([+-])?inf/i)
|
20
|
+
(inf[1] == '-' ? -1.0 : 1.0) / 0.0
|
21
|
+
else
|
22
|
+
Float(str)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rediska.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'rediska/configuration'
|
3
|
+
require 'rediska/connection'
|
4
|
+
|
5
|
+
module Rediska
|
6
|
+
extend self
|
7
|
+
|
8
|
+
attr_accessor :configuration
|
9
|
+
|
10
|
+
def configure
|
11
|
+
Redis::Connection.drivers << Rediska::Connection
|
12
|
+
|
13
|
+
self.configuration ||= Configuration.new
|
14
|
+
yield configuration
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Rediska.configure {}
|
data/rediska.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'rediska/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'rediska'
|
6
|
+
s.version = Rediska::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ['Leonid Beder']
|
9
|
+
s.email = ['leonid.beder@gmail.com']
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.homepage = 'https://github.com/lbeder/rediska'
|
12
|
+
s.summary = 'A light-weighted redis driver for testing, development, and minimal environments'
|
13
|
+
s.description = 'A light-weighted redis driver for testing, development, and minimal environments,
|
14
|
+
which supports various data storage strategies'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_runtime_dependency 'redis', '~> 3.0.0'
|
22
|
+
s.add_development_dependency 'rspec', '~> 2.14'
|
23
|
+
s.add_development_dependency 'coveralls'
|
24
|
+
s.add_development_dependency 'pry'
|
25
|
+
s.add_development_dependency 'pry-debugger'
|
26
|
+
end
|
data/spec/redis_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples 'redis' do
|
4
|
+
it_behaves_like 'compatibility'
|
5
|
+
it_behaves_like 'hashes'
|
6
|
+
it_behaves_like 'connection'
|
7
|
+
it_behaves_like 'keys'
|
8
|
+
it_behaves_like 'lists'
|
9
|
+
it_behaves_like 'server'
|
10
|
+
it_behaves_like 'sets'
|
11
|
+
it_behaves_like 'strings'
|
12
|
+
it_behaves_like 'transactions'
|
13
|
+
it_behaves_like 'sorted sets'
|
14
|
+
it_behaves_like 'upcase method names'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'Rediska' do
|
18
|
+
subject { Redis.new }
|
19
|
+
|
20
|
+
before do
|
21
|
+
Rediska.configure do |config|
|
22
|
+
config.namespace = 'rediska_test'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'fake redis' do
|
27
|
+
context 'memory' do
|
28
|
+
before do
|
29
|
+
subject.flushall
|
30
|
+
end
|
31
|
+
|
32
|
+
it_behaves_like 'redis'
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'PStore' do
|
36
|
+
before do
|
37
|
+
Rediska.configure do |config|
|
38
|
+
config.database = :filesystem
|
39
|
+
end
|
40
|
+
|
41
|
+
subject.flushall
|
42
|
+
end
|
43
|
+
|
44
|
+
it_behaves_like 'redis'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Remove the pending declaration in order to test interoperability with a local instance of redis.
|
49
|
+
pending 'real redis (interoperability)' do
|
50
|
+
before do
|
51
|
+
subject.flushall
|
52
|
+
end
|
53
|
+
|
54
|
+
before(:all) do
|
55
|
+
Redis::Connection.drivers.pop
|
56
|
+
end
|
57
|
+
|
58
|
+
after(:all) do
|
59
|
+
Redis::Connection.drivers << Rediska::Connection
|
60
|
+
end
|
61
|
+
|
62
|
+
it_behaves_like 'redis'
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'coveralls'
|
5
|
+
require 'pry'
|
6
|
+
require 'pry-debugger'
|
7
|
+
require 'rediska'
|
8
|
+
|
9
|
+
Coveralls.wear!
|
10
|
+
|
11
|
+
Dir['./spec/support/*.rb'].each { |f| require f }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.order = 'random'
|
15
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
shared_examples 'connection' do
|
2
|
+
it 'should authenticate to the server' do
|
3
|
+
begin
|
4
|
+
subject.auth('pass').should eq('OK')
|
5
|
+
rescue Redis::CommandError => e
|
6
|
+
raise unless e.message == 'ERR Client sent AUTH, but no password is set'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should re-use the same instance with the same host and port' do
|
11
|
+
subject1 = Redis.new(host: '127.0.0.1', port: 6379)
|
12
|
+
subject2 = Redis.new(host: '127.0.0.1', port: 6379)
|
13
|
+
|
14
|
+
subject1.set('key1', '1')
|
15
|
+
subject2.get('key1').should eq('1')
|
16
|
+
|
17
|
+
subject2.set('key2', '2')
|
18
|
+
subject1.get('key2').should eq('2')
|
19
|
+
|
20
|
+
subject1.get('key3').should be_nil
|
21
|
+
subject2.get('key3').should be_nil
|
22
|
+
|
23
|
+
subject1.dbsize.should eq(2)
|
24
|
+
subject2.dbsize.should eq(2)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should connect to a specific database' do
|
28
|
+
subject1 = Redis.new(host: '127.0.0.1', port: 6379, db: 0)
|
29
|
+
subject1.set('key1', '1')
|
30
|
+
subject1.select(0)
|
31
|
+
subject1.get('key1').should eq('1')
|
32
|
+
|
33
|
+
subject2 = Redis.new(host: '127.0.0.1', port: 6379, db: 1)
|
34
|
+
subject2.set('key1', '1')
|
35
|
+
subject2.select(1)
|
36
|
+
subject2.get('key1').should eq('1')
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should handle multiple clients using the same db instance' do
|
40
|
+
subject1 = Redis.new(host: '127.0.0.1', port: 6379, db: 1)
|
41
|
+
subject2 = Redis.new(host: '127.0.0.1', port: 6379, db: 2)
|
42
|
+
|
43
|
+
subject1.set('key1', 'one')
|
44
|
+
subject1.get('key1').should eq('one')
|
45
|
+
|
46
|
+
subject2.set('key2', 'two')
|
47
|
+
subject2.get('key2').should eq('two')
|
48
|
+
|
49
|
+
subject1.get('key1').should eq('one')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should not error with a disconnected client' do
|
53
|
+
subject1 = Redis.new
|
54
|
+
subject1.client.disconnect
|
55
|
+
subject1.get('key1').should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should echo the given string' do
|
59
|
+
subject.echo('something').should eq('something')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should ping the server' do
|
63
|
+
subject.ping.should eq('PONG')
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
shared_examples 'hashes' do
|
2
|
+
it 'should delete a hash field' do
|
3
|
+
subject.hset('key1', 'k1', 'val1')
|
4
|
+
subject.hset('key1', 'k2', 'val2')
|
5
|
+
subject.hdel('key1', 'k1')
|
6
|
+
|
7
|
+
subject.hget('key1', 'k1').should be_nil
|
8
|
+
subject.hget('key1', 'k2').should eq('val2')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should remove a hash with no keys left' do
|
12
|
+
subject.hset('key1', 'k1', 'val1')
|
13
|
+
subject.hset('key1', 'k2', 'val2')
|
14
|
+
subject.hdel('key1', 'k1')
|
15
|
+
subject.hdel('key1', 'k2')
|
16
|
+
|
17
|
+
subject.exists('key1').should be_false
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should convert key to a string for hset' do
|
21
|
+
m = double('key')
|
22
|
+
m.stub(:to_s).and_return('foo')
|
23
|
+
|
24
|
+
subject.hset('key1', m, 'bar')
|
25
|
+
subject.hget('key1', 'foo').should eq('bar')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should convert key to a string for hget' do
|
29
|
+
m = double('key')
|
30
|
+
m.stub(:to_s).and_return('foo')
|
31
|
+
|
32
|
+
subject.hset('key1', 'foo', 'bar')
|
33
|
+
subject.hget('key1', m).should eq('bar')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should determine if a hash field exists' do
|
37
|
+
subject.hset('key1', 'index', 'value')
|
38
|
+
|
39
|
+
subject.hexists('key1', 'index').should be_true
|
40
|
+
subject.hexists('key2', 'i2').should be_false
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should get the value of a hash field' do
|
44
|
+
subject.hset('key1', 'index', 'value')
|
45
|
+
|
46
|
+
subject.hget('key1', 'index').should eq('value')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should get all the fields and values in a hash' do
|
50
|
+
subject.hset('key1', 'i1', 'val1')
|
51
|
+
subject.hset('key1', 'i2', 'val2')
|
52
|
+
|
53
|
+
subject.hgetall('key1').should eq({'i1' => 'val1', 'i2' => 'val2'})
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should increment the integer value of a hash field by the given number' do
|
57
|
+
subject.hset('key1', 'cont1', '5')
|
58
|
+
subject.hincrby('key1', 'cont1', '5').should eq(10)
|
59
|
+
subject.hget('key1', 'cont1').should eq('10')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should increment non existing hash keys' do
|
63
|
+
subject.hget('key1', 'cont2').should be_nil
|
64
|
+
subject.hincrby('key1', 'cont2', '5').should eq(5)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should get all the fields in a hash' do
|
68
|
+
subject.hset('key1', 'i1', 'val1')
|
69
|
+
subject.hset('key1', 'i2', 'val2')
|
70
|
+
|
71
|
+
subject.hkeys('key1').should eq(['i1', 'i2'])
|
72
|
+
subject.hkeys('key2').should be_empty
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should get the number of fields in a hash' do
|
76
|
+
subject.hset('key1', 'i1', 'val1')
|
77
|
+
subject.hset('key1', 'i2', 'val2')
|
78
|
+
|
79
|
+
subject.hlen('key1').should eq(2)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should get the values of all the given hash fields' do
|
83
|
+
subject.hset('key1', 'i1', 'val1')
|
84
|
+
subject.hset('key1', 'i2', 'val2')
|
85
|
+
|
86
|
+
subject.hmget('key1', 'i1', 'i2', 'i3').should eq(['val1', 'val2', nil])
|
87
|
+
subject.hmget('key2', 'i1', 'i2').should eq([nil, nil])
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should throw an argument error when you do not ask for any keys' do
|
91
|
+
expect {
|
92
|
+
subject.hmget('key1')
|
93
|
+
}.to raise_error(Redis::CommandError)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should reject an empty list of values' do
|
97
|
+
expect {
|
98
|
+
subject.hmset('key')
|
99
|
+
}.to raise_error(Redis::CommandError)
|
100
|
+
|
101
|
+
subject.exists('key').should be_false
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'rejects an insert with a key but no value' do
|
105
|
+
expect {
|
106
|
+
subject.hmset('key', 'foo')
|
107
|
+
}.to raise_error(Redis::CommandError)
|
108
|
+
|
109
|
+
expect {
|
110
|
+
subject.hmset('key', 'foo', 3, 'bar')
|
111
|
+
}.to raise_error(Redis::CommandError)
|
112
|
+
|
113
|
+
subject.exists('key').should be_false
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should reject the wrong number of arguments' do
|
117
|
+
expect {
|
118
|
+
subject.hmset('hash', 'foo1', 'bar1', 'foo2', 'bar2', 'foo3')
|
119
|
+
}.to raise_error(Redis::CommandError)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should set multiple hash fields to multiple values' do
|
123
|
+
subject.hmset('key', 'k1', 'value1', 'k2', 'value2')
|
124
|
+
|
125
|
+
subject.hget('key', 'k1').should eq('value1')
|
126
|
+
subject.hget('key', 'k2').should eq('value2')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should set multiple hash fields from a ruby hash to multiple values' do
|
130
|
+
subject.mapped_hmset('foo', k1: 'value1', k2: 'value2')
|
131
|
+
|
132
|
+
subject.hget('foo', 'k1').should eq('value1')
|
133
|
+
subject.hget('foo', 'k2').should eq('value2')
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should set the string value of a hash field' do
|
137
|
+
subject.hset('key1', 'k1', 'val1').should be_true
|
138
|
+
subject.hset('key1', 'k1', 'val1').should be_false
|
139
|
+
|
140
|
+
subject.hget('key1', 'k1').should eq('val1')
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should set the value of a hash field, only if the field does not exist' do
|
144
|
+
subject.hset('key1', 'k1', 'val1')
|
145
|
+
subject.hsetnx('key1', 'k1', 'value').should be_false
|
146
|
+
subject.hsetnx('key1', 'k2', 'val2').should be_true
|
147
|
+
subject.hsetnx('key1', :k1, 'value').should be_false
|
148
|
+
subject.hsetnx('key1', :k3, 'val3').should be_true
|
149
|
+
|
150
|
+
subject.hget('key1', 'k1').should eq('val1')
|
151
|
+
subject.hget('key1', 'k2').should eq('val2')
|
152
|
+
subject.hget('key1', 'k3').should eq('val3')
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'should get all the values in a hash' do
|
156
|
+
subject.hset('key1', 'k1', 'val1')
|
157
|
+
subject.hset('key1', 'k2', 'val2')
|
158
|
+
|
159
|
+
subject.hvals('key1').should eq(['val1', 'val2'])
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should accept a list of array pairs as arguments and not throw an invalid argument number error' do
|
163
|
+
subject.hmset('key1', [:k1, 'val1'], [:k2, 'val2'], [:k3, 'val3'])
|
164
|
+
subject.hget('key1', :k1).should eq('val1')
|
165
|
+
subject.hget('key1', :k2).should eq('val2')
|
166
|
+
subject.hget('key1', :k3).should eq('val3')
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should reject a list of arrays that contain an invalid number of arguments' do
|
170
|
+
expect {
|
171
|
+
subject.hmset('key1', [:k1, 'val1'], [:k2, 'val2', 'bogus val'])
|
172
|
+
}.to raise_error(Redis::CommandError)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should convert a integer field name to string for hdel' do
|
176
|
+
subject.hset('key1', '1', 1)
|
177
|
+
subject.hdel('key1', 1).should eq(1)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should convert a integer field name to string for hexists' do
|
181
|
+
subject.hset('key1', '1', 1)
|
182
|
+
subject.hexists('key1', 1).should be_true
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should convert a integer field name to string for hincrby' do
|
186
|
+
subject.hset('key1', 1, 0)
|
187
|
+
subject.hincrby('key1', 1, 1).should eq(1)
|
188
|
+
end
|
189
|
+
end
|