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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5efa2877ed6be2aaac8746a197e0c0af6a82684a
4
- data.tar.gz: 30d0a4254f13357960664cf89e8737ec3ac05703
2
+ SHA256:
3
+ metadata.gz: '09a30ec9909bf8d0e289b62a48184649e43a5053e4d38049efc1514fc496d29f'
4
+ data.tar.gz: 211591dea5dc948d4bcb0fece84b33bb6899fe980b87b061daa6bcb44b8d8354
5
5
  SHA512:
6
- metadata.gz: 7c053f2ec1b3b5dfaeaffe3e3319d4c7d3644f3300ca868066ae9bc38f45012299ae14cd5b7b3189f5f2730b8adea503c33dce565b7cb925ec9e07c3ea0b5a79
7
- data.tar.gz: c0ce4d41e22a9215144ebaef7d714720b7567c7729b17c3d3b4305d9e0cbd6573db6f23aad7cf5a848d070e1009e648cd0204d88a6ab5daab39c1c012db1b6d9
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.0.0
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
- * ZSCORE
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.shift.to_s.downcase.to_sym
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, *command]
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, *command)
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
@@ -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(password)
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, Fixnum)
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
- # Sort by score, or if scores are equal, key alphanum
919
- results = data[key].sort do |(k1, v1), (k2, v2)|
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 = queued_commands.map do |cmd|
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 = [] # reset queued_commands
58
- self.in_multi = false # reset in_multi state
57
+ self.queued_commands = []
58
+ self.in_multi = false
59
59
 
60
60
  responses
61
61
  end
@@ -1,3 +1,3 @@
1
1
  module Rediska
2
- VERSION = '0.3.1'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
data/spec/redis_spec.rb CHANGED
@@ -46,7 +46,7 @@ describe 'Rediska' do
46
46
  end
47
47
  end
48
48
 
49
- pending 'real redis (interoperability)' do
49
+ context 'real redis (interoperability)' do
50
50
  before(:all) do
51
51
  Redis::Connection.drivers.pop
52
52
  end
@@ -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 be_falsy
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
@@ -51,7 +51,7 @@ shared_examples 'connection' do
51
51
 
52
52
  it 'should not error with a disconnected client' do
53
53
  subject1 = Redis.new
54
- subject1.client.disconnect
54
+ subject1.disconnect
55
55
  expect(subject1.get('key1')).to be_nil
56
56
  end
57
57
 
@@ -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 be_falsey
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 be_falsey
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 be_falsey
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 be_falsey
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 'should error deleting no keys' do
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
- it "should return true when setnx keys that don't exist" do
30
- expect(subject.setnx('key1', '1')).to be_truthy
31
- end
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 be_falsey
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 be_falsey
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 be_falsey
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 be_falsey
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 be_falsey
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 be_falsey
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 be_falsey
438
+ expect(subject.exists('key1')).to eq(0)
449
439
  end
450
440
 
451
441
  it 'restores to a new key successfully' do
@@ -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 be_falsey
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
@@ -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 be_falsey
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 be_falsey
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 be_falsey
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
@@ -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 be_falsey
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
- it 'zrem should remove members add by zadd' do
446
- subject.zadd('key1', 1, 3)
447
- subject.zrem('key1', 3)
448
- expect(subject.zscore('key1', 3)).to be_nil
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'
@@ -2,8 +2,4 @@ shared_examples 'upcase method names' do
2
2
  it '#ZCOUNT' do
3
3
  expect(subject.ZCOUNT('key', 2, 3)).to eq(subject.zcount('key', 2, 3))
4
4
  end
5
-
6
- it '#ZSCORE' do
7
- expect(subject.ZSCORE('key', 2)).to eq(subject.zscore('key', 2))
8
- end
9
5
  end
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: 0.3.1
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: 2015-07-30 00:00:00.000000000 Z
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
- rubyforge_project:
153
- rubygems_version: 2.4.6
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: