lib/redis/connection/memory.rb in fakeredis-0.4.0 vs lib/redis/connection/memory.rb in fakeredis-0.4.1

- old
+ new

@@ -74,12 +74,16 @@ def connected? @connected end + def self.instances + @instances ||= {} + end + def self.connect(options = {}) - self.new(true) + self.instances[options] ||= self.new(true) end def connect_unix(path, timeout) @connected = true end @@ -179,11 +183,11 @@ @data[key] = value return old_value end def mget(*keys) - raise ArgumentError, "wrong number of arguments for 'mget' command" if keys.empty? + raise Redis::CommandError, "wrong number of arguments for 'mget' command" if keys.empty? @data.values_at(*keys) end def append(key, value) @data[key] = (@data[key] || "") @@ -252,11 +256,11 @@ @data[key].size end def lrange(key, startidx, endidx) data_type_check(key, Array) - @data[key] && @data[key][startidx..endidx] + (@data[key] && @data[key][startidx..endidx]) || [] end def ltrim(key, start, stop) data_type_check(key, Array) return unless @data[key] @@ -273,11 +277,11 @@ return unless @data[key] index = @data[key].index(pivot) case where when :before then @data[key].insert(index, value) when :after then @data[key].insert(index + 1, value) - else raise ArgumentError + else raise Redis::CommandError, "ERR syntax error" end end def lset(key, index, value) data_type_check(key, Array) @@ -305,11 +309,13 @@ end def rpush(key, value) data_type_check(key, Array) @data[key] ||= [] - @data[key].push(value) + [value].flatten.each do |val| + @data[key].push(val.to_s) + end @data[key].size end def rpushx(key, value) data_type_check(key, Array) @@ -318,11 +324,13 @@ end def lpush(key, value) data_type_check(key, Array) @data[key] ||= [] - @data[key].unshift(value) + [value].flatten.each do |val| + @data[key].unshift(val.to_s) + end @data[key].size end def lpushx(key, value) data_type_check(key, Array) @@ -360,16 +368,24 @@ @data[key].include?(value.to_s) end def sadd(key, value) data_type_check(key, ::Set) - if @data[key] - !!@data[key].add?(value.to_s) + value = Array(value) + + result = if @data[key] + old_set = @data[key].dup + @data[key].merge(value.map(&:to_s)) + (@data[key] - old_set).size else - @data[key] = ::Set.new([value.to_s]) - true + @data[key] = ::Set.new(value.map(&:to_s)) + @data[key].size end + + # 0 = false, 1 = true, 2+ untouched + return result == 1 if result < 2 + result end def srem(key, value) data_type_check(key, ::Set) deleted = !!(@data[key] && @data[key].delete?(value.to_s)) @@ -445,12 +461,14 @@ return nil unless @data[key] @data[key].to_a[rand(@data[key].size)] end def del(*keys) + keys = keys.flatten(1) + raise Redis::CommandError, "ERR wrong number of arguments for 'del' command" if keys.empty? old_count = @data.keys.size - keys.flatten.each do |key| + keys.each do |key| @data.delete(key) end deleted_count = old_count - @data.keys.size end @@ -521,20 +539,20 @@ return false if @data[key] && @data[key][field] hset(key, field, value) end def hmset(key, *fields) - raise ArgumentError, "wrong number of arguments for 'hmset' command" if fields.empty? || fields.size.odd? + raise Redis::CommandError, "wrong number of arguments for 'hmset' command" if fields.empty? || fields.size.odd? data_type_check(key, Hash) @data[key] ||= {} fields.each_slice(2) do |field| @data[key][field[0].to_s] = field[1].to_s end end def hmget(key, *fields) - raise ArgumentError, "wrong number of arguments for 'hmget' command" if fields.empty? + raise Redis::CommandError, "wrong number of arguments for 'hmget' command" if fields.empty? data_type_check(key, Hash) values = [] fields.map do |field| field = field.to_s if @data[key] @@ -629,30 +647,26 @@ def sort(key) # TODO: Implement end def incr(key) - @data[key] = (@data[key] || "0") - @data[key] = (@data[key].to_i + 1).to_s + @data.merge!({ key => (@data[key].to_i + 1).to_s || "1"}) @data[key].to_i end def incrby(key, by) - @data[key] = (@data[key] || "0") - @data[key] = (@data[key].to_i + by.to_i).to_s + @data.merge!({ key => (@data[key].to_i + by.to_i).to_s || by }) @data[key].to_i end def decr(key) - @data[key] = (@data[key] || "0") - @data[key] = (@data[key].to_i - 1).to_s + @data.merge!({ key => (@data[key].to_i - 1).to_s || "-1"}) @data[key].to_i end def decrby(key, by) - @data[key] = (@data[key] || "0") - @data[key] = (@data[key].to_i - by.to_i).to_s + @data.merge!({ key => ((@data[key].to_i - by.to_i) || (by.to_i * -1)).to_s }) @data[key].to_i end def type(key) case value = @data[key] @@ -688,16 +702,38 @@ def unwatch "OK" end - def zadd(key, score, value) + def zadd(key, *args) + if !args.first.is_a?(Array) + if args.size < 2 + raise Redis::CommandError, "ERR wrong number of arguments for 'zadd' command" + elsif args.size.odd? + raise Redis::CommandError, "ERR syntax error" + end + else + unless args.all? {|pair| pair.size == 2 } + raise(Redis::CommandError, "ERR syntax error") + end + end + data_type_check(key, ZSet) @data[key] ||= ZSet.new - exists = @data[key].key?(value.to_s) - @data[key][value.to_s] = score - !exists + + if args.size == 2 + score, value = args + exists = !@data[key].key?(value.to_s) + @data[key][value.to_s] = score + else + # Turn [1, 2, 3, 4] into [[1, 2], [3, 4]] unless it is already + args = args.each_slice(2).to_a unless args.first.is_a?(Array) + exists = args.map(&:last).map { |el| @data[key].key?(el.to_s) }.count(false) + args.each { |score, value| @data[key][value.to_s] = score } + end + + exists end def zrem(key, value) data_type_check(key, ZSet) exists = false @@ -809,11 +845,12 @@ data_type_check(out, ZSet) hashes = keys.map do |src| case @data[src] when ::Set - Hash[@data[src].zip([0] * @data[src].size)] + # Every value has a score of 1 + Hash[@data[src].map {|k,v| [k, 1]}] when Hash @data[src] else {} end @@ -828,18 +865,27 @@ @data[out].size end def zremrangebyrank(key, start, stop) sorted_elements = @data[key].sort { |(v_a, r_a), (v_b, r_b)| r_a <=> r_b } + start = sorted_elements.length if start > sorted_elements.length elements_to_delete = sorted_elements[start..stop] elements_to_delete.each { |elem, rank| @data[key].delete(elem) } elements_to_delete.size end private def zrange_select_by_score(key, min, max) - @data[key].reject {|_,v| v < min || v > max } + if min == '-inf' && max == '+inf' + @data[key] + elsif max == '+inf' + @data[key].reject { |_,v| v < min } + elsif min == '-inf' + @data[key].reject { |_,v| v > max } + else + @data[key].reject {|_,v| v < min || v > max } + end end def remove_key_for_empty_collection(key) del(key) if @data[key] && @data[key].empty? end