rediska 0.3.1 → 1.1.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 +5 -5
- data/.travis.yml +3 -4
- data/README.md +2 -2
- data/lib/rediska/command_executor.rb +8 -3
- data/lib/rediska/driver.rb +152 -25
- data/lib/rediska/transaction_commands.rb +4 -4
- data/lib/rediska/version.rb +1 -1
- data/spec/redis_spec.rb +1 -1
- data/spec/support/bitop.rb +1 -1
- data/spec/support/connection.rb +1 -1
- data/spec/support/hashes.rb +53 -4
- data/spec/support/keys.rb +13 -23
- data/spec/support/lists.rb +6 -1
- data/spec/support/server.rb +2 -2
- data/spec/support/sets.rb +39 -1
- data/spec/support/sorted_sets.rb +39 -87
- data/spec/support/upcase_method_names.rb +0 -4
- metadata +6 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '09a30ec9909bf8d0e289b62a48184649e43a5053e4d38049efc1514fc496d29f'
|
4
|
+
data.tar.gz: 211591dea5dc948d4bcb0fece84b33bb6899fe980b87b061daa6bcb44b8d8354
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d0ee50c993ca33227397ad369ce542555422ff9d589e09d3944dd2cc03fb093bc6799c7c139e987b52fc30ae34e986aa743259d4791688bee60763a351c9c2e
|
7
|
+
data.tar.gz: a29a26ffa641cbd11c8cd0569206f1e1547c569a1a365ec7bd8c4bf443afaf5345bbe55917ae7531d5a4d4947bd8b00bf9194dd43990ba59e0df35a7b3e8cad6
|
data/.travis.yml
CHANGED
@@ -2,14 +2,13 @@ language: ruby
|
|
2
2
|
before_install:
|
3
3
|
- travis_retry gem install bundler
|
4
4
|
rvm:
|
5
|
-
- 2.
|
6
|
-
- 2.1.2
|
7
|
-
- 2.2.0
|
5
|
+
- 2.2.2
|
8
6
|
- ruby-head
|
9
7
|
- jruby
|
10
|
-
- rbx-2
|
11
8
|
gemfile:
|
12
9
|
- Gemfile
|
10
|
+
services:
|
11
|
+
- redis-server
|
13
12
|
matrix:
|
14
13
|
allow_failures:
|
15
14
|
- rvm: rbx-2
|
data/README.md
CHANGED
@@ -160,6 +160,7 @@ end
|
|
160
160
|
* SPOP
|
161
161
|
* SRANDMEMBER
|
162
162
|
* SREM
|
163
|
+
* SSCAN
|
163
164
|
* STRLEN
|
164
165
|
* SUNION
|
165
166
|
* SUNIONSTORE
|
@@ -171,7 +172,6 @@ end
|
|
171
172
|
* ZADD
|
172
173
|
* ZCARD
|
173
174
|
* ZCOUNT
|
174
|
-
* ZINCRBY
|
175
175
|
* ZINTERSTORE
|
176
176
|
* ZUNIONSTORE
|
177
177
|
* ZRANK
|
@@ -182,7 +182,7 @@ end
|
|
182
182
|
* ZREVRANGE
|
183
183
|
* ZREVRANGEBYSCORE
|
184
184
|
* ZREVRANK
|
185
|
-
*
|
185
|
+
* ZSCAN
|
186
186
|
|
187
187
|
## Credits and Contributors
|
188
188
|
|
@@ -1,13 +1,16 @@
|
|
1
1
|
module Rediska
|
2
2
|
module CommandExecutor
|
3
3
|
def write(command)
|
4
|
-
meffod = command.
|
4
|
+
meffod = command[0].to_s.downcase.to_sym
|
5
|
+
args = command[1..-1]
|
5
6
|
|
6
7
|
if in_multi && !(TRANSACTION_COMMANDS.include? meffod) # queue commands
|
7
|
-
queued_commands << [meffod, *
|
8
|
+
queued_commands << [meffod, *args]
|
8
9
|
reply = 'QUEUED'
|
10
|
+
elsif respond_to?(meffod) && method(meffod).arity.zero?
|
11
|
+
reply = send(meffod)
|
9
12
|
elsif respond_to?(meffod)
|
10
|
-
reply = send(meffod, *
|
13
|
+
reply = send(meffod, *args)
|
11
14
|
else
|
12
15
|
raise Redis::CommandError, "ERR unknown command '#{meffod}'"
|
13
16
|
end
|
@@ -16,6 +19,8 @@ module Rediska
|
|
16
19
|
reply = 1
|
17
20
|
elsif reply == false
|
18
21
|
reply = 0
|
22
|
+
elsif reply.is_a?(Array)
|
23
|
+
reply = reply.map { |r| r == true ? 1 : r == false ? 0 : r }
|
19
24
|
end
|
20
25
|
|
21
26
|
replies << reply
|
data/lib/rediska/driver.rb
CHANGED
@@ -17,6 +17,16 @@ module Rediska
|
|
17
17
|
def disconnect
|
18
18
|
end
|
19
19
|
|
20
|
+
def client(command, _options = {})
|
21
|
+
case command
|
22
|
+
when :setname then true
|
23
|
+
when :getname then nil
|
24
|
+
when :client then true
|
25
|
+
else
|
26
|
+
raise Redis::CommandError, "ERR unknown command '#{command}'"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
def timeout=(usecs)
|
21
31
|
end
|
22
32
|
|
@@ -43,7 +53,7 @@ module Rediska
|
|
43
53
|
'OK'
|
44
54
|
end
|
45
55
|
|
46
|
-
def auth(
|
56
|
+
def auth(*args)
|
47
57
|
'OK'
|
48
58
|
end
|
49
59
|
|
@@ -198,6 +208,42 @@ module Rediska
|
|
198
208
|
data[key].keys
|
199
209
|
end
|
200
210
|
|
211
|
+
def hscan(key, start_cursor, *args)
|
212
|
+
data_type_check(key, Hash)
|
213
|
+
return ['0', []] unless data[key]
|
214
|
+
|
215
|
+
match = '*'
|
216
|
+
count = 10
|
217
|
+
|
218
|
+
raise_argument_error('hscan') if args.size.odd?
|
219
|
+
|
220
|
+
if idx = args.index('MATCH')
|
221
|
+
match = args[idx + 1]
|
222
|
+
end
|
223
|
+
|
224
|
+
if idx = args.index('COUNT')
|
225
|
+
count = args[idx + 1]
|
226
|
+
end
|
227
|
+
|
228
|
+
start_cursor = start_cursor.to_i
|
229
|
+
|
230
|
+
cursor = start_cursor
|
231
|
+
next_keys = []
|
232
|
+
|
233
|
+
if start_cursor + count >= data[key].length
|
234
|
+
next_keys = (data[key].to_a)[start_cursor..-1]
|
235
|
+
cursor = 0
|
236
|
+
else
|
237
|
+
cursor = start_cursor + count
|
238
|
+
next_keys = (data[key].to_a)[start_cursor..cursor-1]
|
239
|
+
end
|
240
|
+
|
241
|
+
filtered_next_keys = next_keys.select{|k,v| File.fnmatch(match, k)}
|
242
|
+
result = filtered_next_keys.flatten.map(&:to_s)
|
243
|
+
|
244
|
+
return ["#{cursor}", result]
|
245
|
+
end
|
246
|
+
|
201
247
|
def keys(pattern = '*')
|
202
248
|
data.keys.select { |key| File.fnmatch(pattern, key) }
|
203
249
|
end
|
@@ -281,7 +327,7 @@ module Rediska
|
|
281
327
|
|
282
328
|
def lrem(key, count, value)
|
283
329
|
data_type_check(key, Array)
|
284
|
-
return unless data[key]
|
330
|
+
return 0 unless data[key]
|
285
331
|
old_size = data[key].size
|
286
332
|
diff =
|
287
333
|
if count == 0
|
@@ -499,6 +545,44 @@ module Rediska
|
|
499
545
|
number.nil? ? srandmember_single(key) : srandmember_multiple(key, number)
|
500
546
|
end
|
501
547
|
|
548
|
+
def sscan(key, start_cursor, *args)
|
549
|
+
data_type_check(key, ::Set)
|
550
|
+
return ['0', []] unless data[key]
|
551
|
+
|
552
|
+
match = '*'
|
553
|
+
count = 10
|
554
|
+
|
555
|
+
if args.size.odd?
|
556
|
+
raise_argument_error('sscan')
|
557
|
+
end
|
558
|
+
|
559
|
+
if idx = args.index('MATCH')
|
560
|
+
match = args[idx + 1]
|
561
|
+
end
|
562
|
+
|
563
|
+
if idx = args.index('COUNT')
|
564
|
+
count = args[idx + 1]
|
565
|
+
end
|
566
|
+
|
567
|
+
start_cursor = start_cursor.to_i
|
568
|
+
|
569
|
+
cursor = start_cursor
|
570
|
+
next_keys = []
|
571
|
+
|
572
|
+
if start_cursor + count >= data[key].length
|
573
|
+
next_keys = (data[key].to_a)[start_cursor..-1]
|
574
|
+
cursor = 0
|
575
|
+
else
|
576
|
+
cursor = start_cursor + count
|
577
|
+
next_keys = (data[key].to_a)[start_cursor..cursor-1]
|
578
|
+
end
|
579
|
+
|
580
|
+
filtered_next_keys = next_keys.select{ |k,v| File.fnmatch(match, k)}
|
581
|
+
result = filtered_next_keys.flatten.map(&:to_s)
|
582
|
+
|
583
|
+
return ["#{cursor}", result]
|
584
|
+
end
|
585
|
+
|
502
586
|
def del(*keys)
|
503
587
|
keys = keys.flatten(1)
|
504
588
|
raise_argument_error('del') if keys.empty?
|
@@ -813,7 +897,7 @@ module Rediska
|
|
813
897
|
end
|
814
898
|
|
815
899
|
start_cursor = start_cursor.to_i
|
816
|
-
data_type_check(start_cursor,
|
900
|
+
data_type_check(start_cursor, Integer)
|
817
901
|
|
818
902
|
cursor = start_cursor
|
819
903
|
next_keys = []
|
@@ -877,26 +961,12 @@ module Rediska
|
|
877
961
|
data[key] ? data[key].size : 0
|
878
962
|
end
|
879
963
|
|
880
|
-
def zscore(key, value)
|
881
|
-
data_type_check(key, ZSet)
|
882
|
-
value = data[key] && data[key][value.to_s]
|
883
|
-
value && value.to_s
|
884
|
-
end
|
885
|
-
|
886
964
|
def zcount(key, min, max)
|
887
965
|
data_type_check(key, ZSet)
|
888
966
|
return 0 unless data[key]
|
889
967
|
data[key].select_by_score(min, max).size
|
890
968
|
end
|
891
969
|
|
892
|
-
def zincrby(key, num, value)
|
893
|
-
data_type_check(key, ZSet)
|
894
|
-
data[key] ||= ZSet.new
|
895
|
-
data[key][value.to_s] ||= 0
|
896
|
-
data[key].increment(value.to_s, num)
|
897
|
-
data[key][value.to_s].to_s
|
898
|
-
end
|
899
|
-
|
900
970
|
def zrank(key, value)
|
901
971
|
data_type_check(key, ZSet)
|
902
972
|
z = data[key]
|
@@ -915,14 +985,8 @@ module Rediska
|
|
915
985
|
data_type_check(key, ZSet)
|
916
986
|
return [] unless data[key]
|
917
987
|
|
918
|
-
|
919
|
-
|
920
|
-
if v1 == v2
|
921
|
-
k1 <=> k2
|
922
|
-
else
|
923
|
-
v1 <=> v2
|
924
|
-
end
|
925
|
-
end
|
988
|
+
results = sort_keys(data[key])
|
989
|
+
|
926
990
|
# Select just the keys unless we want scores
|
927
991
|
results = results.map(&:first) unless with_scores
|
928
992
|
results[start..stop].flatten.map(&:to_s)
|
@@ -1008,6 +1072,58 @@ module Rediska
|
|
1008
1072
|
data[out].size
|
1009
1073
|
end
|
1010
1074
|
|
1075
|
+
def zscan(key, start_cursor, *args)
|
1076
|
+
data_type_check(key, ZSet)
|
1077
|
+
return [] unless data[key]
|
1078
|
+
|
1079
|
+
match = '*'
|
1080
|
+
count = 10
|
1081
|
+
|
1082
|
+
if args.size.odd?
|
1083
|
+
raise_argument_error('zscan')
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
if idx = args.index('MATCH')
|
1087
|
+
match = args[idx + 1]
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
if idx = args.index('COUNT')
|
1091
|
+
count = args[idx + 1]
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
start_cursor = start_cursor.to_i
|
1095
|
+
data_type_check(start_cursor, Integer)
|
1096
|
+
|
1097
|
+
cursor = start_cursor
|
1098
|
+
next_keys = []
|
1099
|
+
|
1100
|
+
sorted_keys = sort_keys(data[key])
|
1101
|
+
|
1102
|
+
if start_cursor + count >= sorted_keys.length
|
1103
|
+
next_keys = sorted_keys.to_a.select { |k| File.fnmatch(match, k[0]) } [start_cursor..-1]
|
1104
|
+
cursor = 0
|
1105
|
+
else
|
1106
|
+
cursor = start_cursor + count
|
1107
|
+
next_keys = sorted_keys.to_a.select { |k| File.fnmatch(match, k[0]) } [start_cursor..cursor-1]
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
return "#{cursor}", next_keys.flatten.map(&:to_s)
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
# Originally from redis-rb
|
1114
|
+
def zscan_each(key, *args, &block)
|
1115
|
+
data_type_check(key, ZSet)
|
1116
|
+
return [] unless data[key]
|
1117
|
+
|
1118
|
+
return to_enum(:zscan_each, key, options) unless block_given?
|
1119
|
+
cursor = 0
|
1120
|
+
loop do
|
1121
|
+
cursor, values = zscan(key, cursor, options)
|
1122
|
+
values.each(&block)
|
1123
|
+
break if cursor == '0'
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1011
1127
|
private
|
1012
1128
|
def raise_argument_error(command, match_string = command)
|
1013
1129
|
error_message = if %w(hmset mset_odd).include?(match_string.downcase)
|
@@ -1064,5 +1180,16 @@ module Rediska
|
|
1064
1180
|
(1..-number).map { data[key].to_a[rand(data[key].size)] }.flatten
|
1065
1181
|
end
|
1066
1182
|
end
|
1183
|
+
|
1184
|
+
def sort_keys(arr)
|
1185
|
+
# Sort by score, or if scores are equal, key alphanum
|
1186
|
+
arr.sort do |(k1, v1), (k2, v2)|
|
1187
|
+
if v1 == v2
|
1188
|
+
k1 <=> k2
|
1189
|
+
else
|
1190
|
+
v1 <=> v2
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
end
|
1067
1194
|
end
|
1068
1195
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Rediska
|
2
|
-
TRANSACTION_COMMANDS = [:discard, :exec, :multi, :watch, :unwatch]
|
2
|
+
TRANSACTION_COMMANDS = [:discard, :exec, :multi, :watch, :unwatch, :client]
|
3
3
|
|
4
4
|
module TransactionCommands
|
5
5
|
def self.included(klass)
|
@@ -46,7 +46,7 @@ module Rediska
|
|
46
46
|
raise Redis::CommandError, 'ERR EXEC without MULTI'
|
47
47
|
end
|
48
48
|
|
49
|
-
responses
|
49
|
+
responses = queued_commands.map do |cmd|
|
50
50
|
begin
|
51
51
|
send(*cmd)
|
52
52
|
rescue => e
|
@@ -54,8 +54,8 @@ module Rediska
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
self.queued_commands = []
|
58
|
-
self.in_multi = false
|
57
|
+
self.queued_commands = []
|
58
|
+
self.in_multi = false
|
59
59
|
|
60
60
|
responses
|
61
61
|
end
|
data/lib/rediska/version.rb
CHANGED
data/spec/redis_spec.rb
CHANGED
data/spec/support/bitop.rb
CHANGED
@@ -9,7 +9,7 @@ shared_examples_for 'a bitwise operation' do |operator|
|
|
9
9
|
|
10
10
|
it 'should not create destination key if nothing found' do
|
11
11
|
expect(subject.bitop(operator, 'dest1', 'nothing_here1')).to eq(0)
|
12
|
-
expect(subject.exists('dest1')).to
|
12
|
+
expect(subject.exists('dest1')).to eq(0)
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should accept operator as a case-insensitive symbol' do
|
data/spec/support/connection.rb
CHANGED
data/spec/support/hashes.rb
CHANGED
@@ -25,7 +25,7 @@ shared_examples 'hashes' do
|
|
25
25
|
expect(subject.hdel('key1', 'k1')).to eq(1)
|
26
26
|
expect(subject.hdel('key1', 'k2')).to eq(1)
|
27
27
|
|
28
|
-
expect(subject.exists('key1')).to
|
28
|
+
expect(subject.exists('key1')).to eq(0)
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'should convert key to a string for hset' do
|
@@ -122,7 +122,7 @@ shared_examples 'hashes' do
|
|
122
122
|
subject.hmset('key')
|
123
123
|
}.to raise_error(Redis::CommandError)
|
124
124
|
|
125
|
-
expect(subject.exists('key')).to
|
125
|
+
expect(subject.exists('key')).to eq(0)
|
126
126
|
end
|
127
127
|
|
128
128
|
it 'rejects an insert with a key but no value' do
|
@@ -134,7 +134,7 @@ shared_examples 'hashes' do
|
|
134
134
|
subject.hmset('key', 'foo', 3, 'bar')
|
135
135
|
}.to raise_error(Redis::CommandError)
|
136
136
|
|
137
|
-
expect(subject.exists('key')).to
|
137
|
+
expect(subject.exists('key')).to eq(0)
|
138
138
|
end
|
139
139
|
|
140
140
|
it 'should reject the wrong number of arguments' do
|
@@ -159,7 +159,7 @@ shared_examples 'hashes' do
|
|
159
159
|
|
160
160
|
it 'should set the string value of a hash field' do
|
161
161
|
expect(subject.hset('key1', 'k1', 'val1')).to be_truthy
|
162
|
-
expect(subject.hset('key1', 'k1', 'val1')).to
|
162
|
+
expect(subject.hset('key1', 'k1', 'val1')).to eq(0)
|
163
163
|
|
164
164
|
expect(subject.hget('key1', 'k1')).to eq('val1')
|
165
165
|
end
|
@@ -210,4 +210,53 @@ shared_examples 'hashes' do
|
|
210
210
|
subject.hset('key1', 1, 0)
|
211
211
|
expect(subject.hincrby('key1', 1, 1)).to eq(1)
|
212
212
|
end
|
213
|
+
|
214
|
+
describe "#hscan" do
|
215
|
+
it 'with no arguments and few items, returns all items' do
|
216
|
+
subject.hmset('hash', 'name', 'Jack', 'age', '33')
|
217
|
+
result = subject.hscan('hash', 0)
|
218
|
+
|
219
|
+
expect(result[0]).to eq('0')
|
220
|
+
expect(result[1]).to eq([['name', 'Jack'], ['age', '33']])
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'with a count should return that number of members or more' do
|
224
|
+
subject.hmset('hash','a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7')
|
225
|
+
result = subject.hscan('hash', 0, count: 3)
|
226
|
+
expect(result[0]).to eq('3')
|
227
|
+
expect(result[1]).to eq([
|
228
|
+
['a', '1'],
|
229
|
+
['b', '2'],
|
230
|
+
['c', '3'],
|
231
|
+
])
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'returns items starting at the provided cursor' do
|
235
|
+
subject.hmset('hash', 'a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7')
|
236
|
+
result = subject.hscan('hash', 2, count: 3)
|
237
|
+
expect(result[0]).to eq('5')
|
238
|
+
expect(result[1]).to eq([
|
239
|
+
['c', '3'],
|
240
|
+
['d', '4'],
|
241
|
+
['e', '5']
|
242
|
+
])
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'with match, returns items matching the given pattern' do
|
246
|
+
subject.hmset('hash', 'aa', '1', 'b', '2', 'cc', '3', 'd', '4', 'ee', '5', 'f', '6', 'gg', '7')
|
247
|
+
result = subject.hscan('hash', 2, count: 3, match: '??')
|
248
|
+
expect(result[0]).to eq('5')
|
249
|
+
expect(result[1]).to eq([
|
250
|
+
['cc', '3'],
|
251
|
+
['ee', '5']
|
252
|
+
])
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'returns an empty result if the key is not found' do
|
256
|
+
result = subject.hscan('hash', 0)
|
257
|
+
|
258
|
+
expect(result[0]).to eq('0')
|
259
|
+
expect(result[1]).to eq([])
|
260
|
+
end
|
261
|
+
end
|
213
262
|
end
|
data/spec/support/keys.rb
CHANGED
@@ -16,24 +16,14 @@ shared_examples 'keys' do
|
|
16
16
|
expect(subject.get('key2')).to be_nil
|
17
17
|
end
|
18
18
|
|
19
|
-
it
|
20
|
-
expect
|
21
|
-
subject.del
|
22
|
-
}.to raise_error(Redis::CommandError)
|
23
|
-
|
24
|
-
expect {
|
25
|
-
subject.del []
|
26
|
-
}.to raise_error(Redis::CommandError)
|
19
|
+
it "should return true when setnx keys that don't exist" do
|
20
|
+
expect(subject.setnx('key1', '1')).to be_truthy
|
27
21
|
end
|
28
22
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
it 'should return false when setnx keys exist' do
|
34
|
-
subject.set('key1', '1')
|
35
|
-
expect(subject.setnx('key1', '1')).to be_falsey
|
36
|
-
end
|
23
|
+
it 'should return false when setnx keys exist' do
|
24
|
+
subject.set('key1', '1')
|
25
|
+
expect(subject.setnx('key1', '1')).to be_falsey
|
26
|
+
end
|
37
27
|
|
38
28
|
it 'should return true when setting expires on keys that exist' do
|
39
29
|
subject.set('key1', '1')
|
@@ -58,7 +48,7 @@ shared_examples 'keys' do
|
|
58
48
|
subject.set('key1', '1')
|
59
49
|
|
60
50
|
expect(subject.exists('key1')).to be_truthy
|
61
|
-
expect(subject.exists('key2')).to
|
51
|
+
expect(subject.exists('key2')).to eq(0)
|
62
52
|
end
|
63
53
|
|
64
54
|
it "should set a key's time to live in seconds" do
|
@@ -123,7 +113,7 @@ shared_examples 'keys' do
|
|
123
113
|
subject.set('key1', '1')
|
124
114
|
subject.expireat('key1', Time.now.to_i)
|
125
115
|
|
126
|
-
expect(subject.exists('key1')).to
|
116
|
+
expect(subject.exists('key1')).to eq(0)
|
127
117
|
end
|
128
118
|
|
129
119
|
it 'should find all keys matching the given pattern' do
|
@@ -387,13 +377,13 @@ shared_examples 'keys' do
|
|
387
377
|
|
388
378
|
it 'uses nx option to only set the key if it does not already exist' do
|
389
379
|
expect(subject.set('key1', '1', nx: true)).to be_truthy
|
390
|
-
expect(subject.set('key1', '2', nx: true)).to
|
380
|
+
expect(subject.set('key1', '2', nx: true)).to eq(0)
|
391
381
|
|
392
382
|
expect(subject.get('key1')).to eq('1')
|
393
383
|
end
|
394
384
|
|
395
385
|
it 'uses xx option to only set the key if it already exists' do
|
396
|
-
expect(subject.set('key2', '1', xx: true)).to
|
386
|
+
expect(subject.set('key2', '1', xx: true)).to eq(0)
|
397
387
|
subject.set('key2', '2')
|
398
388
|
expect(subject.set('key2', '1', xx: true)).to be_truthy
|
399
389
|
|
@@ -401,13 +391,13 @@ shared_examples 'keys' do
|
|
401
391
|
end
|
402
392
|
|
403
393
|
it 'does not set the key if both xx and nx option are specified' do
|
404
|
-
expect(subject.set('key2', '1', nx: true, xx: true)).to
|
394
|
+
expect(subject.set('key2', '1', nx: true, xx: true)).to eq(0)
|
405
395
|
expect(subject.get('key2')).to be_nil
|
406
396
|
end
|
407
397
|
|
408
398
|
describe '#dump' do
|
409
399
|
it 'returns nil for unknown key' do
|
410
|
-
expect(subject.exists('key1')).to
|
400
|
+
expect(subject.exists('key1')).to eq(0)
|
411
401
|
expect(subject.dump('key1')).to be_nil
|
412
402
|
end
|
413
403
|
|
@@ -445,7 +435,7 @@ shared_examples 'keys' do
|
|
445
435
|
@dumped_value = subject.dump('key1')
|
446
436
|
|
447
437
|
subject.del('key1')
|
448
|
-
expect(subject.exists('key1')).to
|
438
|
+
expect(subject.exists('key1')).to eq(0)
|
449
439
|
end
|
450
440
|
|
451
441
|
it 'restores to a new key successfully' do
|
data/spec/support/lists.rb
CHANGED
@@ -89,13 +89,18 @@ shared_examples 'lists' do
|
|
89
89
|
expect(subject.llen('key1')).to eq(2)
|
90
90
|
end
|
91
91
|
|
92
|
+
it 'should return 0 if key does not map to a list' do
|
93
|
+
expect(subject.exists('nonexistant')).to eq(0)
|
94
|
+
expect(subject.lrem('nonexistant', 0, 'value')).to eq(0)
|
95
|
+
end
|
96
|
+
|
92
97
|
it "should remove list's key when list is empty" do
|
93
98
|
subject.rpush('key1', 'v1')
|
94
99
|
subject.rpush('key1', 'v2')
|
95
100
|
subject.lrem('key1', 1, 'v1')
|
96
101
|
subject.lrem('key1', 1, 'v2')
|
97
102
|
|
98
|
-
expect(subject.exists('key1')).to
|
103
|
+
expect(subject.exists('key1')).to eq(0)
|
99
104
|
end
|
100
105
|
|
101
106
|
it 'should set the value of an element in a list by its index' do
|
data/spec/support/server.rb
CHANGED
@@ -40,12 +40,12 @@ shared_examples 'server' do
|
|
40
40
|
subject.select(0)
|
41
41
|
expect(subject.dbsize).to eq(2)
|
42
42
|
expect(subject.exists('key1')).to be_truthy
|
43
|
-
expect(subject.exists('key3')).to
|
43
|
+
expect(subject.exists('key3')).to eq(0)
|
44
44
|
|
45
45
|
subject.select(1)
|
46
46
|
expect(subject.dbsize).to eq(3)
|
47
47
|
expect(subject.exists('key4')).to be_truthy
|
48
|
-
expect(subject.exists('key2')).to
|
48
|
+
expect(subject.exists('key2')).to eq(0)
|
49
49
|
|
50
50
|
subject.flushall
|
51
51
|
expect(subject.dbsize).to eq(0)
|
data/spec/support/sets.rb
CHANGED
@@ -157,7 +157,7 @@ shared_examples 'sets' do
|
|
157
157
|
subject.srem('key1', 'b')
|
158
158
|
subject.srem('key1', 'a')
|
159
159
|
|
160
|
-
expect(subject.exists('key1')).to
|
160
|
+
expect(subject.exists('key1')).to eq(0)
|
161
161
|
end
|
162
162
|
|
163
163
|
it 'should add multiple sets' do
|
@@ -258,4 +258,42 @@ shared_examples 'sets' do
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
end
|
261
|
+
|
262
|
+
describe 'sscan' do
|
263
|
+
it 'with no arguments and few items, returns all items' do
|
264
|
+
subject.sadd('set', ['name', 'Jack', 'age', '33'])
|
265
|
+
result = subject.sscan('set', 0)
|
266
|
+
|
267
|
+
expect(result[0]).to eq('0')
|
268
|
+
expect(result[1]).to eq(['name', 'Jack', 'age', '33'])
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'with a count should return that number of members or more' do
|
272
|
+
subject.sadd('set', ['a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7'])
|
273
|
+
result = subject.sscan('set', 0, count: 3)
|
274
|
+
expect(result[0]).to eq('3')
|
275
|
+
expect(result[1]).to eq([ 'a', '1', 'b'])
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'returns items starting at the provided cursor' do
|
279
|
+
subject.sadd('set', ['a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7'])
|
280
|
+
result = subject.sscan('set', 2, count: 3)
|
281
|
+
expect(result[0]).to eq('5')
|
282
|
+
expect(result[1]).to eq(['b', '2', 'c'])
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'with match, returns items matching the given pattern' do
|
286
|
+
subject.sadd('set', ['aa', '1', 'b', '2', 'cc', '3', 'd', '4', 'ee', '5', 'f', '6', 'gg', '7'])
|
287
|
+
result = subject.sscan('set', 2, count: 7, match: '??')
|
288
|
+
expect(result[0]).to eq('9')
|
289
|
+
expect(result[1]).to eq(['cc','ee'])
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'returns an empty result if the key is not found' do
|
293
|
+
result = subject.sscan('set', 0)
|
294
|
+
|
295
|
+
expect(result[0]).to eq('0')
|
296
|
+
expect(result[1]).to eq([])
|
297
|
+
end
|
298
|
+
end
|
261
299
|
end
|
data/spec/support/sorted_sets.rb
CHANGED
@@ -1,47 +1,4 @@
|
|
1
1
|
shared_examples 'sorted sets' do
|
2
|
-
let(:infinity) { 1.0 / 0.0 }
|
3
|
-
|
4
|
-
it 'should add a member to a sorted set, or update its score if it already exists' do
|
5
|
-
expect(subject.zadd('key', 1, 'val')).to be_truthy
|
6
|
-
expect(subject.zscore('key', 'val')).to eq(1.0)
|
7
|
-
|
8
|
-
expect(subject.zadd('key', 2, 'val')).to be_falsey
|
9
|
-
expect(subject.zscore('key', 'val')).to eq(2.0)
|
10
|
-
|
11
|
-
expect(subject.zadd('key2', 'inf', 'val')).to be_truthy
|
12
|
-
expect(subject.zscore('key2', 'val')).to eq(infinity)
|
13
|
-
|
14
|
-
expect(subject.zadd('key3', '+inf', 'val')).to be_truthy
|
15
|
-
expect(subject.zscore('key3', 'val')).to eq(infinity)
|
16
|
-
|
17
|
-
expect(subject.zadd('key4', '-inf', 'val')).to be_truthy
|
18
|
-
expect(subject.zscore('key4', 'val')).to eq(-infinity)
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'should return a nil score for value not in a sorted set or empty key' do
|
22
|
-
subject.zadd('key', 1, 'val')
|
23
|
-
|
24
|
-
expect(subject.zscore('key', 'val')).to eq(1.0)
|
25
|
-
expect(subject.zscore('key', 'val2')).to be_nil
|
26
|
-
expect(subject.zscore('key2', 'val')).to be_nil
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should add multiple members to a sorted set, or update its score if it already exists' do
|
30
|
-
expect(subject.zadd('key', [1, 'val', 2, 'val2'])).to eq(2)
|
31
|
-
expect(subject.zscore('key', 'val')).to eq(1)
|
32
|
-
expect(subject.zscore('key', 'val2')).to eq(2)
|
33
|
-
|
34
|
-
expect(subject.zadd('key', [[5, 'val'], [3, 'val3'], [4, 'val4']])).to eq(2)
|
35
|
-
expect(subject.zscore('key', 'val')).to eq(5)
|
36
|
-
expect(subject.zscore('key', 'val2')).to eq(2)
|
37
|
-
expect(subject.zscore('key', 'val3')).to eq(3)
|
38
|
-
expect(subject.zscore('key', 'val4')).to eq(4)
|
39
|
-
|
40
|
-
expect(subject.zadd('key', [[5, 'val5'], [3, 'val6']])).to eq(2)
|
41
|
-
expect(subject.zscore('key', 'val5')).to eq(5)
|
42
|
-
expect(subject.zscore('key', 'val6')).to eq(3)
|
43
|
-
end
|
44
|
-
|
45
2
|
it 'should error with wrong number of arguments when adding members' do
|
46
3
|
expect {
|
47
4
|
subject.zadd('key')
|
@@ -64,14 +21,6 @@ shared_examples 'sorted sets' do
|
|
64
21
|
}.to raise_error(Redis::CommandError)
|
65
22
|
end
|
66
23
|
|
67
|
-
it 'should allow floats as scores when adding or updating' do
|
68
|
-
expect(subject.zadd('key', 4.321, 'val')).to be_truthy
|
69
|
-
expect(subject.zscore('key', 'val')).to eq(4.321)
|
70
|
-
|
71
|
-
expect(subject.zadd('key', 54.3210, 'val')).to be_falsey
|
72
|
-
expect(subject.zscore('key', 'val')).to eq(54.321)
|
73
|
-
end
|
74
|
-
|
75
24
|
it 'should remove members from sorted sets' do
|
76
25
|
expect(subject.zrem('key', 'val')).to be_falsey
|
77
26
|
expect(subject.zadd('key', 1, 'val')).to be_truthy
|
@@ -92,7 +41,7 @@ shared_examples 'sorted sets' do
|
|
92
41
|
it "should remove sorted set's key when it is empty" do
|
93
42
|
subject.zadd('key', 1, 'val')
|
94
43
|
subject.zrem('key', 'val')
|
95
|
-
expect(subject.exists('key')).to
|
44
|
+
expect(subject.exists('key')).to eq(0)
|
96
45
|
end
|
97
46
|
|
98
47
|
it 'should get the number of members in a sorted set' do
|
@@ -111,26 +60,6 @@ shared_examples 'sorted sets' do
|
|
111
60
|
expect(subject.zcount('key', 2, 3)).to eq(2)
|
112
61
|
end
|
113
62
|
|
114
|
-
it 'should increment the score of a member in a sorted set' do
|
115
|
-
subject.zadd('key', 1, 'val1')
|
116
|
-
expect(subject.zincrby('key', 2, 'val1')).to eq(3)
|
117
|
-
expect(subject.zscore('key', 'val1')).to eq(3)
|
118
|
-
end
|
119
|
-
|
120
|
-
it 'initializes the sorted set if the key wasnt already set' do
|
121
|
-
expect(subject.zincrby('key', 1, 'val1')).to eq(1)
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'should convert the key to a string for zscore' do
|
125
|
-
subject.zadd('key', 1, 1)
|
126
|
-
expect(subject.zscore('key', 1)).to eq(1)
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'should handle infinity values when incrementing a sorted set key' do
|
130
|
-
expect(subject.zincrby('bar', '+inf', 's2')).to eq(infinity)
|
131
|
-
expect(subject.zincrby('bar', '-inf', 's1')).to eq(-infinity)
|
132
|
-
end
|
133
|
-
|
134
63
|
it 'should return a range of members in a sorted set, by index' do
|
135
64
|
subject.zadd('key', 1, 'one')
|
136
65
|
subject.zadd('key', 2, 'two')
|
@@ -318,17 +247,6 @@ shared_examples 'sorted sets' do
|
|
318
247
|
expect(subject.zcard('key')).to eq(1)
|
319
248
|
end
|
320
249
|
|
321
|
-
it 'should remove items by score with infinity' do # Issue #50
|
322
|
-
subject.zadd('key', 10.0, 'one')
|
323
|
-
subject.zadd('key', 20.0, 'two')
|
324
|
-
subject.zadd('key', 30.0, 'three')
|
325
|
-
expect(subject.zremrangebyscore('key', '-inf', '+inf')).to eq(3)
|
326
|
-
expect(subject.zcard('key')).to eq(0)
|
327
|
-
expect(subject.zscore('key', 'one')).to be_nil
|
328
|
-
expect(subject.zscore('key', 'two')).to be_nil
|
329
|
-
expect(subject.zscore('key', 'three')).to be_nil
|
330
|
-
end
|
331
|
-
|
332
250
|
it 'should return 0 if the key did not exist' do
|
333
251
|
expect(subject.zremrangebyscore('key', 0, 2)).to eq(0)
|
334
252
|
end
|
@@ -442,10 +360,44 @@ shared_examples 'sorted sets' do
|
|
442
360
|
end
|
443
361
|
end
|
444
362
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
363
|
+
describe '#zscan' do
|
364
|
+
before do
|
365
|
+
50.times { |x| subject.zadd('key', x, "key #{x}") }
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'with no arguments should return 10 numbers in ascending order' do
|
369
|
+
result = subject.zscan('key', 0)[1]
|
370
|
+
expect(result).to eq(result.sort { |x, y| x[1] <=> y[1] })
|
371
|
+
expect(result.count).to eq(10)
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'with a count should return that number of members' do
|
375
|
+
expect(subject.zscan('key', 0, count: 2)).to eq(['2', [['key 0', 0.0], ['key 1', 1.0]]])
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'with a count greater than the number of members, returns all the members in asc order' do
|
379
|
+
result = subject.zscan('key', 0, count: 1000)[1]
|
380
|
+
expect(result).to eq(result.sort { |x, y| x[1] <=> y[1] })
|
381
|
+
expect(result.size).to eq(50)
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'with match, should return key-values where the key matches' do
|
385
|
+
subject.zadd('key', 1.0, 'blah')
|
386
|
+
subject.zadd('key', 2.0, 'bluh')
|
387
|
+
result = subject.zscan('key', 0, count: 100, match: 'key*')[1]
|
388
|
+
expect(result).to_not include(['blah', 1.0])
|
389
|
+
expect(result).to_not include(['bluh', 2.0])
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
describe '#zscan_each' do
|
394
|
+
before do
|
395
|
+
50.times { |x| subject.zadd('key', x, "key #{x}") }
|
396
|
+
end
|
397
|
+
|
398
|
+
it 'enumerates over the items in the sorted set' do
|
399
|
+
expect(subject.zscan_each('key').to_a).to eq(subject.zscan('key', 0, count: 50)[1])
|
400
|
+
end
|
449
401
|
end
|
450
402
|
|
451
403
|
#it 'should remove all members in a sorted set within the given indexes'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rediska
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leonid Beder
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -134,7 +134,7 @@ homepage: https://github.com/lbeder/rediska
|
|
134
134
|
licenses:
|
135
135
|
- MIT
|
136
136
|
metadata: {}
|
137
|
-
post_install_message:
|
137
|
+
post_install_message:
|
138
138
|
rdoc_options: []
|
139
139
|
require_paths:
|
140
140
|
- lib
|
@@ -149,9 +149,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
149
|
- !ruby/object:Gem::Version
|
150
150
|
version: '0'
|
151
151
|
requirements: []
|
152
|
-
|
153
|
-
|
154
|
-
signing_key:
|
152
|
+
rubygems_version: 3.1.6
|
153
|
+
signing_key:
|
155
154
|
specification_version: 4
|
156
155
|
summary: A light-weighted redis driver for testing, development, and minimal environments
|
157
156
|
test_files:
|
@@ -172,4 +171,3 @@ test_files:
|
|
172
171
|
- spec/support/strings.rb
|
173
172
|
- spec/support/transactions.rb
|
174
173
|
- spec/support/upcase_method_names.rb
|
175
|
-
has_rdoc:
|