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.
@@ -0,0 +1,910 @@
1
+ module Rediska
2
+ module Driver
3
+ attr_accessor :buffer, :database_id
4
+ attr_writer :replies
5
+
6
+ def replies
7
+ @replies ||= []
8
+ end
9
+
10
+ def connected?
11
+ true
12
+ end
13
+
14
+ def connect_unix(path, timeout)
15
+ end
16
+
17
+ def disconnect
18
+ end
19
+
20
+ def timeout=(usecs)
21
+ end
22
+
23
+ def write(command)
24
+ meffod = command.shift.to_s.downcase.to_sym
25
+ if respond_to?(meffod)
26
+ reply = send(meffod, *command)
27
+ else
28
+ raise Redis::CommandError, "ERR unknown command #{meffod.upcase}"
29
+ end
30
+
31
+ if reply == true
32
+ reply = 1
33
+ elsif reply == false
34
+ reply = 0
35
+ end
36
+
37
+ replies << reply
38
+ buffer << reply if buffer && meffod != :multi
39
+ nil
40
+ end
41
+
42
+ def read
43
+ replies.shift
44
+ end
45
+
46
+ # NOT IMPLEMENTED:
47
+ # * blpop
48
+ # * brpop
49
+ # * brpoplpush
50
+ # * discard
51
+ # * sort
52
+ # * subscribe
53
+ # * psubscribe
54
+ # * publish
55
+
56
+ def flushdb
57
+ db_class.flushdb(database_instance_key, database_id)
58
+ databases.delete_at(database_id)
59
+
60
+ 'OK'
61
+ end
62
+
63
+ def flushall
64
+ db_class.flushall(database_instance_key)
65
+ self.class.databases[database_instance_key] = []
66
+
67
+ 'OK'
68
+ end
69
+
70
+ def auth(password)
71
+ 'OK'
72
+ end
73
+
74
+ def select(index)
75
+ data_type_check(index, Integer)
76
+ self.database_id = index
77
+
78
+ 'OK'
79
+ end
80
+
81
+ def info
82
+ {
83
+ 'redis_version' => '3.0.5',
84
+ }
85
+ end
86
+
87
+ def monitor
88
+ end
89
+
90
+ def save
91
+ end
92
+
93
+ def bgsave
94
+ end
95
+
96
+ def bgreriteaof
97
+ end
98
+
99
+ def move key, destination_id
100
+ raise Redis::CommandError, 'ERR source and destination objects are the same' if destination_id == database_id
101
+ destination = find_database(destination_id)
102
+ return false unless data.has_key?(key)
103
+ return false if destination.has_key?(key)
104
+ destination[key] = data.delete(key)
105
+ true
106
+ end
107
+
108
+ def get(key)
109
+ data_type_check(key, String)
110
+ data[key]
111
+ end
112
+
113
+ def getbit(key, offset)
114
+ return unless data[key]
115
+ data[key].unpack('B*')[0].split('')[offset].to_i
116
+ end
117
+
118
+ def getrange(key, start, ending)
119
+ return unless data[key]
120
+ data[key][start..ending]
121
+ end
122
+ alias :substr :getrange
123
+
124
+ def getset(key, value)
125
+ data_type_check(key, String)
126
+ data[key].tap do
127
+ set(key, value)
128
+ end
129
+ end
130
+
131
+ def mget(*keys)
132
+ raise_argument_error('mget') if keys.empty?
133
+
134
+ # We work with either an array, or list of arguments
135
+ keys = keys.first if keys.size == 1
136
+ data.values_at(*keys)
137
+ end
138
+
139
+ def append(key, value)
140
+ data[key] = (data[key] || '')
141
+ data[key] = data[key] + value.to_s
142
+ end
143
+
144
+ def strlen(key)
145
+ return unless data[key]
146
+ data[key].size
147
+ end
148
+
149
+ def hgetall(key)
150
+ data_type_check(key, Hash)
151
+ data[key].to_a.flatten || {}
152
+ end
153
+
154
+ def hget(key, field)
155
+ data_type_check(key, Hash)
156
+ data[key] && data[key][field.to_s]
157
+ end
158
+
159
+ def hdel(key, field)
160
+ field = field.to_s
161
+ data_type_check(key, Hash)
162
+ data[key] && data[key].delete(field)
163
+ remove_key_for_empty_collection(key)
164
+ end
165
+
166
+ def hkeys(key)
167
+ data_type_check(key, Hash)
168
+ return [] if data[key].nil?
169
+ data[key].keys
170
+ end
171
+
172
+ def keys(pattern = '*')
173
+ data.keys.select { |key| File.fnmatch(pattern, key) }
174
+ end
175
+
176
+ def randomkey
177
+ data.keys[rand(dbsize)]
178
+ end
179
+
180
+ def echo(string)
181
+ string
182
+ end
183
+
184
+ def ping
185
+ 'PONG'
186
+ end
187
+
188
+ def lastsave
189
+ Time.now.to_i
190
+ end
191
+
192
+ def dbsize
193
+ data.keys.count
194
+ end
195
+
196
+ def exists(key)
197
+ data.key?(key)
198
+ end
199
+
200
+ def llen(key)
201
+ data_type_check(key, Array)
202
+ return 0 unless data[key]
203
+ data[key].size
204
+ end
205
+
206
+ def lrange(key, startidx, endidx)
207
+ data_type_check(key, Array)
208
+ (data[key] && data[key][startidx..endidx]) || []
209
+ end
210
+
211
+ def ltrim(key, start, stop)
212
+ data_type_check(key, Array)
213
+ return unless data[key]
214
+
215
+ if start < 0 && data[key].count < start.abs
216
+ # Example: we have a list of 3 elements and we give it a ltrim list, -5, -1. This means it
217
+ # should trim to a max of 5. Since 3 < 5 we should not touch the list. This is consistent
218
+ # with behavior of real Redis's ltrim with a negative start argument.
219
+ data[key]
220
+ else
221
+ data[key] = data[key][start..stop]
222
+ end
223
+ end
224
+
225
+ def lindex(key, index)
226
+ data_type_check(key, Array)
227
+ data[key] && data[key][index]
228
+ end
229
+
230
+ def linsert(key, where, pivot, value)
231
+ data_type_check(key, Array)
232
+ return unless data[key]
233
+ index = data[key].index(pivot)
234
+ case where
235
+ when :before then data[key].insert(index, value)
236
+ when :after then data[key].insert(index + 1, value)
237
+ else raise_syntax_error
238
+ end
239
+ end
240
+
241
+ def lset(key, index, value)
242
+ data_type_check(key, Array)
243
+ return unless data[key]
244
+ raise Redis::CommandError, 'ERR index out of range' if index >= data[key].size
245
+ data[key][index] = value
246
+ end
247
+
248
+ def lrem(key, count, value)
249
+ data_type_check(key, Array)
250
+ return unless data[key]
251
+ old_size = data[key].size
252
+ diff =
253
+ if count == 0
254
+ data[key].delete(value)
255
+ old_size - data[key].size
256
+ else
257
+ array = count > 0 ? data[key].dup : data[key].reverse
258
+ count.abs.times{ array.delete_at(array.index(value) || array.length) }
259
+ data[key] = count > 0 ? array.dup : array.reverse
260
+ old_size - data[key].size
261
+ end
262
+ remove_key_for_empty_collection(key)
263
+ diff
264
+ end
265
+
266
+ def rpush(key, value)
267
+ data_type_check(key, Array)
268
+ data[key] ||= []
269
+ [value].flatten.each do |val|
270
+ data[key].push(val.to_s)
271
+ end
272
+ data[key].size
273
+ end
274
+
275
+ def rpushx(key, value)
276
+ data_type_check(key, Array)
277
+ return unless data[key]
278
+ rpush(key, value)
279
+ end
280
+
281
+ def lpush(key, value)
282
+ data_type_check(key, Array)
283
+ data[key] ||= []
284
+ [value].flatten.each do |val|
285
+ data[key].unshift(val.to_s)
286
+ end
287
+ data[key].size
288
+ end
289
+
290
+ def lpushx(key, value)
291
+ data_type_check(key, Array)
292
+ return unless data[key]
293
+ lpush(key, value)
294
+ end
295
+
296
+ def rpop(key)
297
+ data_type_check(key, Array)
298
+ return unless data[key]
299
+ data[key].pop
300
+ end
301
+
302
+ def rpoplpush(key1, key2)
303
+ data_type_check(key1, Array)
304
+ rpop(key1).tap do |elem|
305
+ lpush(key2, elem)
306
+ end
307
+ end
308
+
309
+ def lpop(key)
310
+ data_type_check(key, Array)
311
+ return unless data[key]
312
+ data[key].shift
313
+ end
314
+
315
+ def smembers(key)
316
+ data_type_check(key, ::Set)
317
+ return [] unless data[key]
318
+ data[key].to_a.reverse
319
+ end
320
+
321
+ def sismember(key, value)
322
+ data_type_check(key, ::Set)
323
+ return false unless data[key]
324
+ data[key].include?(value.to_s)
325
+ end
326
+
327
+ def sadd(key, value)
328
+ data_type_check(key, ::Set)
329
+ value = Array(value)
330
+ raise_argument_error('sadd') if value.empty?
331
+
332
+ result = if data[key]
333
+ old_set = data[key].dup
334
+ data[key].merge(value.map(&:to_s))
335
+ (data[key] - old_set).size
336
+ else
337
+ data[key] = ::Set.new(value.map(&:to_s))
338
+ data[key].size
339
+ end
340
+
341
+ # 0 = false, 1 = true, 2+ untouched
342
+ return result == 1 if result < 2
343
+ result
344
+ end
345
+
346
+ def srem(key, value)
347
+ data_type_check(key, ::Set)
348
+ deleted = !!(data[key] && data[key].delete?(value.to_s))
349
+ remove_key_for_empty_collection(key)
350
+ deleted
351
+ end
352
+
353
+ def smove(source, destination, value)
354
+ data_type_check(destination, ::Set)
355
+ result = self.srem(source, value)
356
+ self.sadd(destination, value) if result
357
+ result
358
+ end
359
+
360
+ def spop(key)
361
+ data_type_check(key, ::Set)
362
+ elem = srandmember(key)
363
+ srem(key, elem)
364
+ elem
365
+ end
366
+
367
+ def scard(key)
368
+ data_type_check(key, ::Set)
369
+ return 0 unless data[key]
370
+ data[key].size
371
+ end
372
+
373
+ def sinter(*keys)
374
+ raise_argument_error('sinter') if keys.empty?
375
+
376
+ keys.each { |k| data_type_check(k, ::Set) }
377
+ return ::Set.new if keys.any? { |k| data[k].nil? }
378
+ keys = keys.map { |k| data[k] || ::Set.new }
379
+ keys.inject do |set, key|
380
+ set & key
381
+ end.to_a
382
+ end
383
+
384
+ def sinterstore(destination, *keys)
385
+ data_type_check(destination, ::Set)
386
+ result = sinter(*keys)
387
+ data[destination] = ::Set.new(result)
388
+ end
389
+
390
+ def sunion(*keys)
391
+ keys.each { |k| data_type_check(k, ::Set) }
392
+ keys = keys.map { |k| data[k] || ::Set.new }
393
+ keys.inject(::Set.new) do |set, key|
394
+ set | key
395
+ end.to_a
396
+ end
397
+
398
+ def sunionstore(destination, *keys)
399
+ data_type_check(destination, ::Set)
400
+ result = sunion(*keys)
401
+ data[destination] = ::Set.new(result)
402
+ end
403
+
404
+ def sdiff(key1, *keys)
405
+ [key1, *keys].each { |k| data_type_check(k, ::Set) }
406
+ keys = keys.map { |k| data[k] || ::Set.new }
407
+ keys.inject(data[key1]) do |memo, set|
408
+ memo - set
409
+ end.to_a
410
+ end
411
+
412
+ def sdiffstore(destination, key1, *keys)
413
+ data_type_check(destination, ::Set)
414
+ result = sdiff(key1, *keys)
415
+ data[destination] = ::Set.new(result)
416
+ end
417
+
418
+ def srandmember(key)
419
+ data_type_check(key, ::Set)
420
+ return nil unless data[key]
421
+ data[key].to_a[rand(data[key].size)]
422
+ end
423
+
424
+ def del(*keys)
425
+ keys = keys.flatten(1)
426
+ raise_argument_error('del') if keys.empty?
427
+
428
+ old_count = data.keys.size
429
+ keys.each do |key|
430
+ data.delete(key)
431
+ end
432
+ old_count - data.keys.size
433
+ end
434
+
435
+ def setnx(key, value)
436
+ if exists(key)
437
+ false
438
+ else
439
+ set(key, value)
440
+ true
441
+ end
442
+ end
443
+
444
+ def rename(key, new_key)
445
+ return unless data[key]
446
+ data[new_key] = data[key]
447
+ data.expires[new_key] = data.expires[key] if data.expires.include?(key)
448
+ data.delete(key)
449
+ end
450
+
451
+ def renamenx(key, new_key)
452
+ if exists(new_key)
453
+ false
454
+ else
455
+ rename(key, new_key)
456
+ true
457
+ end
458
+ end
459
+
460
+ def expire(key, ttl)
461
+ return unless data[key]
462
+ data.expires[key] = Time.now + ttl
463
+ true
464
+ end
465
+
466
+ def ttl(key)
467
+ if data.expires.include?(key) && (ttl = data.expires[key].to_i - Time.now.to_i) > 0
468
+ ttl
469
+ else
470
+ -1
471
+ end
472
+ end
473
+
474
+ def expireat(key, timestamp)
475
+ data.expires[key] = Time.at(timestamp)
476
+ true
477
+ end
478
+
479
+ def persist(key)
480
+ !!data.expires.delete(key)
481
+ end
482
+
483
+ def hset(key, field, value)
484
+ data_type_check(key, Hash)
485
+ field = field.to_s
486
+ if data[key]
487
+ result = !data[key].include?(field)
488
+ data[key][field] = value.to_s
489
+ result
490
+ else
491
+ data[key] = { field => value.to_s }
492
+ true
493
+ end
494
+ end
495
+
496
+ def hsetnx(key, field, value)
497
+ data_type_check(key, Hash)
498
+ field = field.to_s
499
+ return false if data[key] && data[key][field]
500
+ hset(key, field, value)
501
+ end
502
+
503
+ def hmset(key, *fields)
504
+ fields = fields[0] if mapped_param?(fields)
505
+ raise_argument_error('hmset') if fields.empty?
506
+
507
+ is_list_of_arrays = fields.all?{|field| field.instance_of?(Array)}
508
+
509
+ raise_argument_error('hmset') if fields.size.odd? and !is_list_of_arrays
510
+ raise_argument_error('hmset') if is_list_of_arrays and !fields.all?{|field| field.length == 2}
511
+
512
+ data_type_check(key, Hash)
513
+ data[key] ||= {}
514
+
515
+ if is_list_of_arrays
516
+ fields.each do |pair|
517
+ data[key][pair[0].to_s] = pair[1].to_s
518
+ end
519
+ else
520
+ fields.each_slice(2) do |field|
521
+ data[key][field[0].to_s] = field[1].to_s
522
+ end
523
+ end
524
+ end
525
+
526
+ def hmget(key, *fields)
527
+ raise_argument_error('hmget') if fields.empty?
528
+
529
+ data_type_check(key, Hash)
530
+ fields.map do |field|
531
+ field = field.to_s
532
+ if data[key]
533
+ data[key][field]
534
+ else
535
+ nil
536
+ end
537
+ end
538
+ end
539
+
540
+ def hlen(key)
541
+ data_type_check(key, Hash)
542
+ return 0 unless data[key]
543
+ data[key].size
544
+ end
545
+
546
+ def hvals(key)
547
+ data_type_check(key, Hash)
548
+ return [] unless data[key]
549
+ data[key].values
550
+ end
551
+
552
+ def hincrby(key, field, increment)
553
+ data_type_check(key, Hash)
554
+ field = field.to_s
555
+ if data[key]
556
+ data[key][field] = (data[key][field].to_i + increment.to_i).to_s
557
+ else
558
+ data[key] = { field => increment.to_s }
559
+ end
560
+ data[key][field].to_i
561
+ end
562
+
563
+ def hexists(key, field)
564
+ data_type_check(key, Hash)
565
+ return false unless data[key]
566
+ data[key].key?(field.to_s)
567
+ end
568
+
569
+ def sync ; end
570
+
571
+ def [](key)
572
+ get(key)
573
+ end
574
+
575
+ def []=(key, value)
576
+ set(key, value)
577
+ end
578
+
579
+ def set(key, value)
580
+ data[key] = value.to_s
581
+
582
+ 'OK'
583
+ end
584
+
585
+ def setbit(key, offset, bit)
586
+ old_val = data[key] ? data[key].unpack('B*')[0].split('') : []
587
+ size_increment = [((offset/8)+1)*8-old_val.length, 0].max
588
+ old_val += Array.new(size_increment).map{'0'}
589
+ original_val = old_val[offset]
590
+ old_val[offset] = bit.to_s
591
+ new_val = ''
592
+ old_val.each_slice(8){|b| new_val = new_val + b.join('').to_i(2).chr }
593
+ data[key] = new_val
594
+ original_val
595
+ end
596
+
597
+ def setex(key, seconds, value)
598
+ data[key] = value.to_s
599
+ expire(key, seconds)
600
+
601
+ 'OK'
602
+ end
603
+
604
+ def setrange(key, offset, value)
605
+ return unless data[key]
606
+ s = data[key][offset,value.size]
607
+ data[key][s] = value
608
+ end
609
+
610
+ def mset(*pairs)
611
+ # Handle pairs for mapped_mset command
612
+ pairs = pairs[0] if mapped_param?(pairs)
613
+ raise_argument_error('mset') if pairs.empty? || pairs.size.odd?
614
+
615
+ pairs.each_slice(2) do |pair|
616
+ data[pair[0].to_s] = pair[1].to_s
617
+ end
618
+
619
+ 'OK'
620
+ end
621
+
622
+ def msetnx(*pairs)
623
+ # Handle pairs for mapped_msetnx command
624
+ pairs = pairs[0] if mapped_param?(pairs)
625
+ keys = []
626
+ pairs.each_with_index{|item, index| keys << item.to_s if index % 2 == 0}
627
+ return false if keys.any?{|key| data.key?(key) }
628
+ mset(*pairs)
629
+ true
630
+ end
631
+
632
+ def sort(key)
633
+ # TODO: Implement
634
+ end
635
+
636
+ def incr(key)
637
+ data.merge!({ key => (data[key].to_i + 1).to_s || '1'})
638
+ data[key].to_i
639
+ end
640
+
641
+ def incrby(key, by)
642
+ data.merge!({ key => (data[key].to_i + by.to_i).to_s || by })
643
+ data[key].to_i
644
+ end
645
+
646
+ def decr(key)
647
+ data.merge!({ key => (data[key].to_i - 1).to_s || '-1'})
648
+ data[key].to_i
649
+ end
650
+
651
+ def decrby(key, by)
652
+ data.merge!({ key => ((data[key].to_i - by.to_i) || (by.to_i * -1)).to_s })
653
+ data[key].to_i
654
+ end
655
+
656
+ def type(key)
657
+ case data[key]
658
+ when nil
659
+ 'none'
660
+ when String
661
+ 'string'
662
+ when Hash
663
+ 'hash'
664
+ when Array
665
+ 'list'
666
+ when ::Set
667
+ 'set'
668
+ end
669
+ end
670
+
671
+ def quit
672
+ end
673
+
674
+ def shutdown
675
+ end
676
+
677
+ def slaveof(host, port)
678
+ end
679
+
680
+ def exec
681
+ buffer.tap {|x| self.buffer = nil }
682
+ end
683
+
684
+ def multi
685
+ self.buffer = []
686
+ yield if block_given?
687
+
688
+ 'OK'
689
+ end
690
+
691
+ def watch(_)
692
+ 'OK'
693
+ end
694
+
695
+ def unwatch
696
+ 'OK'
697
+ end
698
+
699
+ def zadd(key, *args)
700
+ if !args.first.is_a?(Array)
701
+ if args.size < 2
702
+ raise_argument_error('zadd')
703
+ elsif args.size.odd?
704
+ raise_syntax_error
705
+ end
706
+ else
707
+ unless args.all? {|pair| pair.size == 2 }
708
+ raise_syntax_error
709
+ end
710
+ end
711
+
712
+ data_type_check(key, ZSet)
713
+ data[key] ||= ZSet.new
714
+
715
+ if args.size == 2 && !(Array === args.first)
716
+ score, value = args
717
+ exists = !data[key].key?(value.to_s)
718
+ data[key][value.to_s] = score
719
+ else
720
+ # Turn [1, 2, 3, 4] into [[1, 2], [3, 4]] unless it is already
721
+ args = args.each_slice(2).to_a unless args.first.is_a?(Array)
722
+ exists = args.map(&:last).map { |el| data[key].key?(el.to_s) }.count(false)
723
+ args.each { |s, v| data[key][v.to_s] = s }
724
+ end
725
+
726
+ exists
727
+ end
728
+
729
+ def zrem(key, value)
730
+ data_type_check(key, ZSet)
731
+ values = Array(value)
732
+ return 0 unless data[key]
733
+
734
+ response = values.map do |v|
735
+ data[key].delete(v) if data[key].has_key?(v)
736
+ end.compact.size
737
+
738
+ remove_key_for_empty_collection(key)
739
+ response
740
+ end
741
+
742
+ def zcard(key)
743
+ data_type_check(key, ZSet)
744
+ data[key] ? data[key].size : 0
745
+ end
746
+
747
+ def zscore(key, value)
748
+ data_type_check(key, ZSet)
749
+ value = data[key] && data[key][value.to_s]
750
+ value && value.to_s
751
+ end
752
+
753
+ def zcount(key, min, max)
754
+ data_type_check(key, ZSet)
755
+ return 0 unless data[key]
756
+ data[key].select_by_score(min, max).size
757
+ end
758
+
759
+ def zincrby(key, num, value)
760
+ data_type_check(key, ZSet)
761
+ data[key] ||= ZSet.new
762
+ data[key][value.to_s] ||= 0
763
+ data[key].increment(value.to_s, num)
764
+ data[key][value.to_s].to_s
765
+ end
766
+
767
+ def zrank(key, value)
768
+ data_type_check(key, ZSet)
769
+ z = data[key]
770
+ return unless z
771
+ z.keys.sort_by {|k| z[k] }.index(value.to_s)
772
+ end
773
+
774
+ def zrevrank(key, value)
775
+ data_type_check(key, ZSet)
776
+ z = data[key]
777
+ return unless z
778
+ z.keys.sort_by {|k| -z[k] }.index(value.to_s)
779
+ end
780
+
781
+ def zrange(key, start, stop, with_scores = nil)
782
+ data_type_check(key, ZSet)
783
+ return [] unless data[key]
784
+
785
+ # Sort by score, or if scores are equal, key alphanum
786
+ results = data[key].sort do |(k1, v1), (k2, v2)|
787
+ if v1 == v2
788
+ k1 <=> k2
789
+ else
790
+ v1 <=> v2
791
+ end
792
+ end
793
+ # Select just the keys unless we want scores
794
+ results = results.map(&:first) unless with_scores
795
+ results[start..stop].flatten.map(&:to_s)
796
+ end
797
+
798
+ def zrevrange(key, start, stop, with_scores = nil)
799
+ data_type_check(key, ZSet)
800
+ return [] unless data[key]
801
+
802
+ if with_scores
803
+ data[key].sort_by {|_,v| -v }
804
+ else
805
+ data[key].keys.sort_by {|k| -data[key][k] }
806
+ end[start..stop].flatten.map(&:to_s)
807
+ end
808
+
809
+ def zrangebyscore(key, min, max, *opts)
810
+ data_type_check(key, ZSet)
811
+ return [] unless data[key]
812
+
813
+ range = data[key].select_by_score(min, max)
814
+ vals = if opts.include?('WITHSCORES')
815
+ range.sort_by {|_,v| v }
816
+ else
817
+ range.keys.sort_by {|k| range[k] }
818
+ end
819
+
820
+ limit = get_limit(opts, vals)
821
+ vals = vals[*limit] if limit
822
+
823
+ vals.flatten.map(&:to_s)
824
+ end
825
+
826
+ def zrevrangebyscore(key, max, min, *opts)
827
+ data_type_check(key, ZSet)
828
+ return [] unless data[key]
829
+
830
+ range = data[key].select_by_score(min, max)
831
+ vals = if opts.include?('WITHSCORES')
832
+ range.sort_by {|_,v| -v }
833
+ else
834
+ range.keys.sort_by {|k| -range[k] }
835
+ end
836
+
837
+ limit = get_limit(opts, vals)
838
+ vals = vals[*limit] if limit
839
+
840
+ vals.flatten.map(&:to_s)
841
+ end
842
+
843
+ def zremrangebyscore(key, min, max)
844
+ data_type_check(key, ZSet)
845
+ return 0 unless data[key]
846
+
847
+ range = data[key].select_by_score(min, max)
848
+ range.each {|k,_| data[key].delete(k) }
849
+ range.size
850
+ end
851
+
852
+ def zinterstore(out, *args)
853
+ data_type_check(out, ZSet)
854
+ args_handler = SortedSetArgumentHandler.new(args)
855
+ data[out] = SortedSetIntersectStore.new(args_handler, data).call
856
+ data[out].size
857
+ end
858
+
859
+ def zunionstore(out, *args)
860
+ data_type_check(out, ZSet)
861
+ args_handler = SortedSetArgumentHandler.new(args)
862
+ data[out] = SortedSetUnionStore.new(args_handler, data).call
863
+ data[out].size
864
+ end
865
+
866
+ def zremrangebyrank(key, start, stop)
867
+ sorted_elements = data[key].sort_by { |k, v| v }
868
+ start = sorted_elements.length if start > sorted_elements.length
869
+ elements_to_delete = sorted_elements[start..stop]
870
+ elements_to_delete.each { |elem, rank| data[key].delete(elem) }
871
+ elements_to_delete.size
872
+ end
873
+
874
+ private
875
+ def raise_argument_error command
876
+ raise Redis::CommandError, "ERR wrong number of arguments for #{command.upcase}"
877
+ end
878
+
879
+ def raise_syntax_error
880
+ raise Redis::CommandError, 'ERR syntax error'
881
+ end
882
+
883
+ def remove_key_for_empty_collection(key)
884
+ del(key) if data[key] && data[key].empty?
885
+ end
886
+
887
+ def data_type_check(key, klass)
888
+ if data[key] && !data[key].is_a?(klass)
889
+ raise Redis::CommandError.new('ERR Operation against a key holding the wrong kind of value')
890
+ end
891
+ end
892
+
893
+ def get_limit(opts, vals)
894
+ index = opts.index('LIMIT')
895
+
896
+ if index
897
+ offset = opts[index + 1]
898
+
899
+ count = opts[index + 2]
900
+ count = vals.size if count < 0
901
+
902
+ [offset, count]
903
+ end
904
+ end
905
+
906
+ def mapped_param? param
907
+ param.size == 1 && param[0].is_a?(Array)
908
+ end
909
+ end
910
+ end