rediska 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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