class Redis::Connection::File

Constants

DB_FOLDER
DB_PATH
FILENAME_PREFIX
FILENAME_SUFIX

try use “db” folder, if the folder not exists, use the same folder

Attributes

buffer[RW]
database_id[W]
options[RW]
replies[W]

Public Class Methods

connect(options = {}) click to toggle source
# File lib/redis/connection/file.rb, line 31
def self.connect(options = {})
  new(options)
end
new(options = {}) click to toggle source
# File lib/redis/connection/file.rb, line 35
def initialize(options = {})
  self.options = options
end
reset_all_databases() click to toggle source

Used for resetting everything in specs

# File lib/redis/connection/file.rb, line 27
def self.reset_all_databases
  ::File.open(DB_PATH, 'wb') { |file| Marshal.dump({}, file) }
end

Public Instance Methods

[](key) click to toggle source
# File lib/redis/connection/file.rb, line 629
def [](key)
  get(key)
end
[]=(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 633
def []=(key, value)
  set(key, value)
end
append(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 192
def append(key, value)
  data[key] = (data[key] || "")
  data[key] = data[key] + value.to_s
end
auth(password) click to toggle source
# File lib/redis/connection/file.rb, line 120
def auth(password)
  "OK"
end
bgreriteaof() click to toggle source
# File lib/redis/connection/file.rb, line 151
def bgreriteaof ; end
bgsave() click to toggle source
# File lib/redis/connection/file.rb, line 149
def bgsave ; end
connect_unix(path, timeout) click to toggle source
# File lib/redis/connection/file.rb, line 66
def connect_unix(path, timeout)
end
connected?() click to toggle source
# File lib/redis/connection/file.rb, line 62
def connected?
  true
end
data() click to toggle source
# File lib/redis/connection/file.rb, line 53
def data
  find_database
end
database_id() click to toggle source
# File lib/redis/connection/file.rb, line 39
def database_id
  @database_id ||= 0
end
database_instance_key() click to toggle source
# File lib/redis/connection/file.rb, line 44
def database_instance_key
  Digest::MD5.hexdigest([options[:host], options[:port]].to_s)
end
dbsize() click to toggle source
# File lib/redis/connection/file.rb, line 246
def dbsize
  data.keys.count
end
decr(key) click to toggle source
# File lib/redis/connection/file.rb, line 701
def decr(key)
  data.merge!({ key => (data[key].to_i - 1).to_s || "-1"})
  data[key].to_i
end
decrby(key, by) click to toggle source
# File lib/redis/connection/file.rb, line 706
def decrby(key, by)
  data.merge!({ key => ((data[key].to_i - by.to_i) || (by.to_i * -1)).to_s })
  data[key].to_i
end
del(*keys) click to toggle source
# File lib/redis/connection/file.rb, line 481
def del(*keys)
  keys = keys.flatten(1)
  raise_argument_error('del') if keys.empty?

  old_count = data.keys.size
  keys.each do |key|
    data.delete(key)
  end
  old_count - data.keys.size
end
disconnect() click to toggle source
# File lib/redis/connection/file.rb, line 69
def disconnect
end
echo(string) click to toggle source
# File lib/redis/connection/file.rb, line 234
def echo(string)
  string
end
exec() click to toggle source
# File lib/redis/connection/file.rb, line 727
def exec
  buffer.tap {|x| self.buffer = nil }
end
exists(key) click to toggle source
# File lib/redis/connection/file.rb, line 250
def exists(key)
  data.key?(key)
end
expire(key, ttl) click to toggle source
# File lib/redis/connection/file.rb, line 517
def expire(key, ttl)
  return unless data[key]
  data.expires[key] = Time.now + ttl
  true
end
expireat(key, timestamp) click to toggle source
# File lib/redis/connection/file.rb, line 531
def expireat(key, timestamp)
  data.expires[key] = Time.at(timestamp)
  true
end
find_database(id=database_id) click to toggle source
# File lib/redis/connection/file.rb, line 48
def find_database id=database_id
  @databases[database_instance_key] ||= {}
  @databases[database_instance_key][id] ||= ExpiringHash.new
end
flushall() click to toggle source
# File lib/redis/connection/file.rb, line 115
def flushall
  @databases[database_instance_key] = {}
  "OK"
end
flushdb() click to toggle source

NOT IMPLEMENTED:

  • blpop

  • brpop

  • brpoplpush

  • discard

  • sort

  • subscribe

  • psubscribe

  • publish

# File lib/redis/connection/file.rb, line 110
def flushdb
  @databases[database_instance_key].delete(database_id)
  "OK"
end
get(key) click to toggle source
# File lib/redis/connection/file.rb, line 162
def get(key)
  data_type_check(key, String)
  data[key]
end
getbit(key, offset) click to toggle source
# File lib/redis/connection/file.rb, line 167
def getbit(key, offset)
  return unless data[key]
  data[key].unpack('B*')[0].split("")[offset].to_i
end
getrange(key, start, ending) click to toggle source
# File lib/redis/connection/file.rb, line 172
def getrange(key, start, ending)
  return unless data[key]
  data[key][start..ending]
end
Also aliased as: substr
getset(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 178
def getset(key, value)
  data_type_check(key, String)
  data[key].tap do
    set(key, value)
  end
end
hdel(key, field) click to toggle source
# File lib/redis/connection/file.rb, line 212
def hdel(key, field)
  field = field.to_s
  data_type_check(key, Hash)
  data[key] && data[key].delete(field)
  remove_key_for_empty_collection(key)
end
hexists(key, field) click to toggle source
# File lib/redis/connection/file.rb, line 621
def hexists(key, field)
  data_type_check(key, Hash)
  return false unless data[key]
  data[key].key?(field.to_s)
end
hget(key, field) click to toggle source
# File lib/redis/connection/file.rb, line 207
def hget(key, field)
  data_type_check(key, Hash)
  data[key] && data[key][field.to_s]
end
hgetall(key) click to toggle source
# File lib/redis/connection/file.rb, line 202
def hgetall(key)
  data_type_check(key, Hash)
  data[key].to_a.flatten || {}
end
hincrby(key, field, increment) click to toggle source
# File lib/redis/connection/file.rb, line 610
def hincrby(key, field, increment)
  data_type_check(key, Hash)
  field = field.to_s
  if data[key]
    data[key][field] = (data[key][field].to_i + increment.to_i).to_s
  else
    data[key] = { field => increment.to_s }
  end
  data[key][field].to_i
end
hkeys(key) click to toggle source
# File lib/redis/connection/file.rb, line 219
def hkeys(key)
  data_type_check(key, Hash)
  return [] if data[key].nil?
  data[key].keys
end
hlen(key) click to toggle source
# File lib/redis/connection/file.rb, line 598
def hlen(key)
  data_type_check(key, Hash)
  return 0 unless data[key]
  data[key].size
end
hmget(key, *fields) click to toggle source
# File lib/redis/connection/file.rb, line 584
def hmget(key, *fields)
  raise_argument_error('hmget')  if fields.empty?

  data_type_check(key, Hash)
  fields.map do |field|
    field = field.to_s
    if data[key]
      data[key][field]
    else
      nil
    end
  end
end
hmset(key, *fields) click to toggle source
# File lib/redis/connection/file.rb, line 560
def hmset(key, *fields)
  # mapped_hmset gives us [[:k1, "v1", :k2, "v2"]] for `fields`. Fix that.
  fields = fields[0] if mapped_param?(fields)
  raise_argument_error('hmset') if fields.empty?

  is_list_of_arrays = fields.all?{|field| field.instance_of?(Array)}

  raise_argument_error('hmset') if fields.size.odd? and !is_list_of_arrays
  raise_argument_error('hmset') if is_list_of_arrays and !fields.all?{|field| field.length == 2}

  data_type_check(key, Hash)
  data[key] ||= {}

  if is_list_of_arrays
    fields.each do |pair|
      data[key][pair[0].to_s] = pair[1].to_s
    end
  else
    fields.each_slice(2) do |field|
      data[key][field[0].to_s] = field[1].to_s
    end
  end
end
hset(key, field, value) click to toggle source
# File lib/redis/connection/file.rb, line 540
def hset(key, field, value)
  data_type_check(key, Hash)
  field = field.to_s
  if data[key]
    result = !data[key].include?(field)
    data[key][field] = value.to_s
    result
  else
    data[key] = { field => value.to_s }
    true
  end
end
hsetnx(key, field, value) click to toggle source
# File lib/redis/connection/file.rb, line 553
def hsetnx(key, field, value)
  data_type_check(key, Hash)
  field = field.to_s
  return false if data[key] && data[key][field]
  hset(key, field, value)
end
hvals(key) click to toggle source
# File lib/redis/connection/file.rb, line 604
def hvals(key)
  data_type_check(key, Hash)
  return [] unless data[key]
  data[key].values
end
incr(key) click to toggle source
# File lib/redis/connection/file.rb, line 691
def incr(key)
  data.merge!({ key => (data[key].to_i + 1).to_s || "1"})
  data[key].to_i
end
incrby(key, by) click to toggle source
# File lib/redis/connection/file.rb, line 696
def incrby(key, by)
  data.merge!({ key => (data[key].to_i + by.to_i).to_s || by })
  data[key].to_i
end
info() click to toggle source
# File lib/redis/connection/file.rb, line 130
def info
  {
    "redis_version" => "0.07",
    "connected_clients" => "1",
    "connected_slaves" => "0",
    "used_memory" => "3187",
    "changes_since_last_save" => "0",
    "last_save_time" => "1237655729",
    "total_connections_received" => "1",
    "total_commands_processed" => "1",
    "uptime_in_seconds" => "36000",
    "uptime_in_days" => 0
  }
end
keys(pattern = "*") click to toggle source
# File lib/redis/connection/file.rb, line 225
def keys(pattern = "*")
  regexp = Regexp.new(pattern.split("*").map { |r| Regexp.escape(r) }.join(".*"))
  data.keys.select { |key| key =~ regexp }
end
lastsave() click to toggle source
# File lib/redis/connection/file.rb, line 242
def lastsave
  Time.now.to_i
end
lindex(key, index) click to toggle source
# File lib/redis/connection/file.rb, line 282
def lindex(key, index)
  data_type_check(key, Array)
  data[key] && data[key][index]
end
linsert(key, where, pivot, value) click to toggle source
# File lib/redis/connection/file.rb, line 287
def linsert(key, where, pivot, value)
  data_type_check(key, Array)
  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_syntax_error
  end
end
llen(key) click to toggle source
# File lib/redis/connection/file.rb, line 254
def llen(key)
  data_type_check(key, Array)
  return 0 unless data[key]
  data[key].size
end
lpop(key) click to toggle source
# File lib/redis/connection/file.rb, line 366
def lpop(key)
  data_type_check(key, Array)
  return unless data[key]
  data[key].shift
end
lpush(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 338
def lpush(key, value)
  data_type_check(key, Array)
  data[key] ||= []
  [value].flatten.each do |val|
    data[key].unshift(val.to_s)
  end
  data[key].size
end
lpushx(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 347
def lpushx(key, value)
  data_type_check(key, Array)
  return unless data[key]
  lpush(key, value)
end
lrange(key, startidx, endidx) click to toggle source
# File lib/redis/connection/file.rb, line 260
def lrange(key, startidx, endidx)
  data_type_check(key, Array)
  (data[key] && data[key][startidx..endidx]) || []
end
lrem(key, count, value) click to toggle source
# File lib/redis/connection/file.rb, line 305
def lrem(key, count, value)
  data_type_check(key, Array)
  return unless data[key]
  old_size = data[key].size
  diff =
    if count == 0
      data[key].delete(value)
      old_size - data[key].size
    else
      array = count > 0 ? data[key].dup : data[key].reverse
      count.abs.times{ array.delete_at(array.index(value) || array.length) }
      data[key] = count > 0 ? array.dup : array.reverse
      old_size - data[key].size
    end
  remove_key_for_empty_collection(key)
  diff
end
lset(key, index, value) click to toggle source
# File lib/redis/connection/file.rb, line 298
def lset(key, index, value)
  data_type_check(key, Array)
  return unless data[key]
  raise Redis::CommandError, "ERR index out of range" if index >= data[key].size
  data[key][index] = value
end
ltrim(key, start, stop) click to toggle source
# File lib/redis/connection/file.rb, line 265
def ltrim(key, start, stop)
  data_type_check(key, Array)
  return unless data[key]

  if start < 0 && data[key].count < start.abs
    # Example: we have a list of 3 elements and
    # we give it a ltrim list, -5, -1. This means
    # it should trim to a max of 5. Since 3 < 5
    # we should not touch the list. This is consistent
    # with behavior of real Redis's ltrim with a negative
    # start argument.
    data[key]
  else
    data[key] = data[key][start..stop]
  end
end
mget(*keys) click to toggle source
# File lib/redis/connection/file.rb, line 185
def mget(*keys)
  raise_argument_error('mget') if keys.empty?
  # We work with either an array, or list of arguments
  keys = keys.first if keys.size == 1
  data.values_at(*keys)
end
monitor() click to toggle source
# File lib/redis/connection/file.rb, line 145
def monitor; end
move(key, destination_id) click to toggle source
# File lib/redis/connection/file.rb, line 153
def move key, destination_id
  raise Redis::CommandError, "ERR source and destination objects are the same" if destination_id == database_id
  destination = find_database(destination_id)
  return false unless data.has_key?(key)
  return false if destination.has_key?(key)
  destination[key] = data.delete(key)
  true
end
mset(*pairs) click to toggle source
# File lib/redis/connection/file.rb, line 666
def mset(*pairs)
  # Handle pairs for mapped_mset command
  pairs = pairs[0] if mapped_param?(pairs)
  raise_argument_error('mset') if pairs.empty? || pairs.size.odd?

  pairs.each_slice(2) do |pair|
    data[pair[0].to_s] = pair[1].to_s
  end
  "OK"
end
msetnx(*pairs) click to toggle source
# File lib/redis/connection/file.rb, line 677
def msetnx(*pairs)
  # Handle pairs for mapped_msetnx command
  pairs = pairs[0] if mapped_param?(pairs)
  keys = []
  pairs.each_with_index{|item, index| keys << item.to_s if index % 2 == 0}
  return false if keys.any?{|key| data.key?(key) }
  mset(*pairs)
  true
end
multi() { || ... } click to toggle source
# File lib/redis/connection/file.rb, line 731
def multi
  self.buffer = []
  yield if block_given?
  "OK"
end
persist(key) click to toggle source
# File lib/redis/connection/file.rb, line 536
def persist(key)
  !!data.expires.delete(key)
end
ping() click to toggle source
# File lib/redis/connection/file.rb, line 238
def ping
  "PONG"
end
quit() click to toggle source
# File lib/redis/connection/file.rb, line 721
def quit ; end
randomkey() click to toggle source
# File lib/redis/connection/file.rb, line 230
def randomkey
  data.keys[rand(dbsize)]
end
read() click to toggle source
# File lib/redis/connection/file.rb, line 96
def read
  replies.shift
end
rename(key, new_key) click to toggle source
# File lib/redis/connection/file.rb, line 501
def rename(key, new_key)
  return unless data[key]
  data[new_key] = data[key]
  data.expires[new_key] = data.expires[key] if data.expires.include?(key)
  data.delete(key)
end
renamenx(key, new_key) click to toggle source
# File lib/redis/connection/file.rb, line 508
def renamenx(key, new_key)
  if exists(new_key)
    false
  else
    rename(key, new_key)
    true
  end
end
replies() click to toggle source
# File lib/redis/connection/file.rb, line 57
def replies
  @replies ||= []
end
rpop(key) click to toggle source
# File lib/redis/connection/file.rb, line 353
def rpop(key)
  data_type_check(key, Array)
  return unless data[key]
  data[key].pop
end
rpoplpush(key1, key2) click to toggle source
# File lib/redis/connection/file.rb, line 359
def rpoplpush(key1, key2)
  data_type_check(key1, Array)
  rpop(key1).tap do |elem|
    lpush(key2, elem)
  end
end
rpush(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 323
def rpush(key, value)
  data_type_check(key, Array)
  data[key] ||= []
  [value].flatten.each do |val|
    data[key].push(val.to_s)
  end
  data[key].size
end
rpushx(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 332
def rpushx(key, value)
  data_type_check(key, Array)
  return unless data[key]
  rpush(key, value)
end
sadd(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 384
def sadd(key, value)
  data_type_check(key, ::Set)
  value = Array(value)
  raise_argument_error('sadd') if value.empty?

  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.map(&:to_s))
    data[key].size
  end

  # 0 = false, 1 = true, 2+ untouched
  return result == 1 if result < 2
  result
end
save() click to toggle source
# File lib/redis/connection/file.rb, line 147
def save; end
scard(key) click to toggle source
# File lib/redis/connection/file.rb, line 424
def scard(key)
  data_type_check(key, ::Set)
  return 0 unless data[key]
  data[key].size
end
sdiff(key1, *keys) click to toggle source
# File lib/redis/connection/file.rb, line 461
def sdiff(key1, *keys)
  [key1, *keys].each { |k| data_type_check(k, ::Set) }
  keys = keys.map { |k| data[k] || ::Set.new }
  keys.inject(data[key1]) do |memo, set|
    memo - set
  end.to_a
end
sdiffstore(destination, key1, *keys) click to toggle source
# File lib/redis/connection/file.rb, line 469
def sdiffstore(destination, key1, *keys)
  data_type_check(destination, ::Set)
  result = sdiff(key1, *keys)
  data[destination] = ::Set.new(result)
end
select(index) click to toggle source
# File lib/redis/connection/file.rb, line 124
def select(index)
  data_type_check(index, Integer)
  self.database_id = index
  "OK"
end
set(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 637
def set(key, value)
  data[key] = value.to_s
  "OK"
end
setbit(key, offset, bit) click to toggle source
# File lib/redis/connection/file.rb, line 642
def setbit(key, offset, bit)
  old_val = data[key] ? data[key].unpack('B*')[0].split("") : []
  size_increment = [((offset/8)+1)*8-old_val.length, 0].max
  old_val += Array.new(size_increment).map{"0"}
  original_val = old_val[offset]
  old_val[offset] = bit.to_s
  new_val = ""
  old_val.each_slice(8){|b| new_val = new_val + b.join("").to_i(2).chr }
  data[key] = new_val
  original_val
end
setex(key, seconds, value) click to toggle source
# File lib/redis/connection/file.rb, line 654
def setex(key, seconds, value)
  data[key] = value.to_s
  expire(key, seconds)
  "OK"
end
setnx(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 492
def setnx(key, value)
  if exists(key)
    false
  else
    set(key, value)
    true
  end
end
setrange(key, offset, value) click to toggle source
# File lib/redis/connection/file.rb, line 660
def setrange(key, offset, value)
  return unless data[key]
  s = data[key][offset,value.size]
  data[key][s] = value
end
shutdown() click to toggle source
# File lib/redis/connection/file.rb, line 723
def shutdown; end
sinter(*keys) click to toggle source
# File lib/redis/connection/file.rb, line 430
def sinter(*keys)
  raise_argument_error('sinter') if keys.empty?

  keys.each { |k| data_type_check(k, ::Set) }
  return ::Set.new if keys.any? { |k| data[k].nil? }
  keys = keys.map { |k| data[k] || ::Set.new }
  keys.inject do |set, key|
    set & key
  end.to_a
end
sinterstore(destination, *keys) click to toggle source
# File lib/redis/connection/file.rb, line 441
def sinterstore(destination, *keys)
  data_type_check(destination, ::Set)
  result = sinter(*keys)
  data[destination] = ::Set.new(result)
end
sismember(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 378
def sismember(key, value)
  data_type_check(key, ::Set)
  return false unless data[key]
  data[key].include?(value.to_s)
end
slaveof(host, port) click to toggle source
# File lib/redis/connection/file.rb, line 725
def slaveof(host, port) ; end
smembers(key) click to toggle source
# File lib/redis/connection/file.rb, line 372
def smembers(key)
  data_type_check(key, ::Set)
  return [] unless data[key]
  data[key].to_a.reverse
end
smove(source, destination, value) click to toggle source
# File lib/redis/connection/file.rb, line 410
def smove(source, destination, value)
  data_type_check(destination, ::Set)
  result = self.srem(source, value)
  self.sadd(destination, value) if result
  result
end
sort(key) click to toggle source
# File lib/redis/connection/file.rb, line 687
def sort(key)
  # TODO: Implement
end
spop(key) click to toggle source
# File lib/redis/connection/file.rb, line 417
def spop(key)
  data_type_check(key, ::Set)
  elem = srandmember(key)
  srem(key, elem)
  elem
end
srandmember(key) click to toggle source
# File lib/redis/connection/file.rb, line 475
def srandmember(key)
  data_type_check(key, ::Set)
  return nil unless data[key]
  data[key].to_a[rand(data[key].size)]
end
srem(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 403
def srem(key, value)
  data_type_check(key, ::Set)
  deleted = !!(data[key] && data[key].delete?(value.to_s))
  remove_key_for_empty_collection(key)
  deleted
end
strlen(key) click to toggle source
# File lib/redis/connection/file.rb, line 197
def strlen(key)
  return unless data[key]
  data[key].size
end
substr(key, start, ending)
Alias for: getrange
sunion(*keys) click to toggle source
# File lib/redis/connection/file.rb, line 447
def sunion(*keys)
  keys.each { |k| data_type_check(k, ::Set) }
  keys = keys.map { |k| data[k] || ::Set.new }
  keys.inject(::Set.new) do |set, key|
    set | key
  end.to_a
end
sunionstore(destination, *keys) click to toggle source
# File lib/redis/connection/file.rb, line 455
def sunionstore(destination, *keys)
  data_type_check(destination, ::Set)
  result = sunion(*keys)
  data[destination] = ::Set.new(result)
end
sync() click to toggle source
# File lib/redis/connection/file.rb, line 627
def sync ; end
timeout=(usecs) click to toggle source
# File lib/redis/connection/file.rb, line 72
def timeout=(usecs)
end
ttl(key) click to toggle source
# File lib/redis/connection/file.rb, line 523
def ttl(key)
  if data.expires.include?(key) && (ttl = data.expires[key].to_i - Time.now.to_i) > 0
    ttl
  else
    -1
  end
end
type(key) click to toggle source
# File lib/redis/connection/file.rb, line 711
def type(key)
  case data[key]
    when nil then "none"
    when String then "string"
    when Hash then "hash"
    when Array then "list"
    when ::Set then "set"
  end
end
unwatch() click to toggle source
# File lib/redis/connection/file.rb, line 741
def unwatch
  "OK"
end
watch(_) click to toggle source
# File lib/redis/connection/file.rb, line 737
def watch(_)
  "OK"
end
write(command) click to toggle source
# File lib/redis/connection/file.rb, line 75
def write(command)
  meffod = command.shift.to_s.downcase.to_sym
  if respond_to?(meffod)
    @databases = ::File.open(DB_PATH) { |file| Marshal.load(file) }
    reply = send(meffod, *command)
    ::File.open(DB_PATH, 'wb') { |file| Marshal.dump(@databases, file) }
  else
    raise Redis::CommandError, "ERR unknown command '#{meffod}'"
  end

  if reply == true
    reply = 1
  elsif reply == false
    reply = 0
  end

  replies << reply
  buffer << reply if buffer && meffod != :multi
  nil
end
zadd(key, *args) click to toggle source
# File lib/redis/connection/file.rb, line 745
def zadd(key, *args)
  if !args.first.is_a?(Array)
    if args.size < 2
      raise_argument_error('zadd')
    elsif args.size.odd?
      raise_syntax_error
    end
  else
    unless args.all? {|pair| pair.size == 2 }
      raise_syntax_error
    end
  end

  data_type_check(key, ZSet)
  data[key] ||= ZSet.new

  if args.size == 2 && !(Array === args.first)
    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 { |s, v| data[key][v.to_s] = s }
  end

  exists
end
zcard(key) click to toggle source
# File lib/redis/connection/file.rb, line 788
def zcard(key)
  data_type_check(key, ZSet)
  data[key] ? data[key].size : 0
end
zcount(key, min, max) click to toggle source
# File lib/redis/connection/file.rb, line 799
def zcount(key, min, max)
  data_type_check(key, ZSet)
  return 0 unless data[key]
  data[key].select_by_score(min, max).size
end
zincrby(key, num, value) click to toggle source
# File lib/redis/connection/file.rb, line 805
def zincrby(key, num, value)
  data_type_check(key, ZSet)
  data[key] ||= ZSet.new
  data[key][value.to_s] ||= 0
  data[key].increment(value.to_s, num)
  data[key][value.to_s].to_s
end
zinterstore(out, *args) click to toggle source
# File lib/redis/connection/file.rb, line 898
def zinterstore(out, *args)
  data_type_check(out, ZSet)
  args_handler = SortedSetArgumentHandler.new(args)
  data[out] = SortedSetIntersectStore.new(args_handler, data).call
  data[out].size
end
zrange(key, start, stop, with_scores = nil) click to toggle source
# File lib/redis/connection/file.rb, line 827
def zrange(key, start, stop, with_scores = nil)
  data_type_check(key, ZSet)
  return [] unless data[key]

  # Sort by score, or if scores are equal, key alphanum
  results = data[key].sort do |(k1, v1), (k2, v2)|
    if v1 == v2
      k1 <=> k2
    else
      v1 <=> v2
    end
  end
  # Select just the keys unless we want scores
  results = results.map(&:first) unless with_scores
  results[start..stop].flatten.map(&:to_s)
end
zrangebyscore(key, min, max, *opts) click to toggle source
# File lib/redis/connection/file.rb, line 855
def zrangebyscore(key, min, max, *opts)
  data_type_check(key, ZSet)
  return [] unless data[key]

  range = data[key].select_by_score(min, max)
  vals = if opts.include?('WITHSCORES')
    range.sort_by {|_,v| v }
  else
    range.keys.sort_by {|k| range[k] }
  end

  limit = get_limit(opts, vals)
  vals = vals[*limit] if limit

  vals.flatten.map(&:to_s)
end
zrank(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 813
def zrank(key, value)
  data_type_check(key, ZSet)
  z = data[key]
  return unless z
  z.keys.sort_by {|k| z[k] }.index(value.to_s)
end
zrem(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 775
def zrem(key, value)
  data_type_check(key, ZSet)
  values = Array(value)
  return 0 unless data[key]

  response = values.map do |v|
    data[key].delete(v) if data[key].has_key?(v)
  end.compact.size

  remove_key_for_empty_collection(key)
  response
end
zremrangebyrank(key, start, stop) click to toggle source
# File lib/redis/connection/file.rb, line 912
def zremrangebyrank(key, start, stop)
  sorted_elements = data[key].sort_by { |k, v| v }
  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
zremrangebyscore(key, min, max) click to toggle source
# File lib/redis/connection/file.rb, line 889
def zremrangebyscore(key, min, max)
  data_type_check(key, ZSet)
  return 0 unless data[key]

  range = data[key].select_by_score(min, max)
  range.each {|k,_| data[key].delete(k) }
  range.size
end
zrevrange(key, start, stop, with_scores = nil) click to toggle source
# File lib/redis/connection/file.rb, line 844
def zrevrange(key, start, stop, with_scores = nil)
  data_type_check(key, ZSet)
  return [] unless data[key]

  if with_scores
    data[key].sort_by {|_,v| -v }
  else
    data[key].keys.sort_by {|k| -data[key][k] }
  end[start..stop].flatten.map(&:to_s)
end
zrevrangebyscore(key, max, min, *opts) click to toggle source
# File lib/redis/connection/file.rb, line 872
def zrevrangebyscore(key, max, min, *opts)
  data_type_check(key, ZSet)
  return [] unless data[key]

  range = data[key].select_by_score(min, max)
  vals = if opts.include?('WITHSCORES')
    range.sort_by {|_,v| -v }
  else
    range.keys.sort_by {|k| -range[k] }
  end

  limit = get_limit(opts, vals)
  vals = vals[*limit] if limit

  vals.flatten.map(&:to_s)
end
zrevrank(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 820
def zrevrank(key, value)
  data_type_check(key, ZSet)
  z = data[key]
  return unless z
  z.keys.sort_by {|k| -z[k] }.index(value.to_s)
end
zscore(key, value) click to toggle source
# File lib/redis/connection/file.rb, line 793
def zscore(key, value)
  data_type_check(key, ZSet)
  value = data[key] && data[key][value.to_s]
  value && value.to_s
end
zunionstore(out, *args) click to toggle source
# File lib/redis/connection/file.rb, line 905
def zunionstore(out, *args)
  data_type_check(out, ZSet)
  args_handler = SortedSetArgumentHandler.new(args)
  data[out] = SortedSetUnionStore.new(args_handler, data).call
  data[out].size
end

Private Instance Methods

data_type_check(key, klass) click to toggle source
# File lib/redis/connection/file.rb, line 933
def data_type_check(key, klass)
  if data[key] && !data[key].is_a?(klass)
    warn "Operation against a key holding the wrong kind of value: Expected #{klass} at #{key}."
    raise Redis::CommandError.new("ERR Operation against a key holding the wrong kind of value")
  end
end
get_limit(opts, vals) click to toggle source
# File lib/redis/connection/file.rb, line 940
def get_limit(opts, vals)
  index = opts.index('LIMIT')

  if index
    offset = opts[index + 1]

    count = opts[index + 2]
    count = vals.size if count < 0

    [offset, count]
  end
end
mapped_param?(param) click to toggle source
# File lib/redis/connection/file.rb, line 953
def mapped_param? param
  param.size == 1 && param[0].is_a?(Array)
end
raise_argument_error(command) click to toggle source
# File lib/redis/connection/file.rb, line 921
def raise_argument_error command
  raise Redis::CommandError, "ERR wrong number of arguments for '#{command}' command"
end
raise_syntax_error() click to toggle source
# File lib/redis/connection/file.rb, line 925
def raise_syntax_error
  raise Redis::CommandError, "ERR syntax error"
end
remove_key_for_empty_collection(key) click to toggle source
# File lib/redis/connection/file.rb, line 929
def remove_key_for_empty_collection(key)
  del(key) if data[key] && data[key].empty?
end