class MockRedis::Database

Attributes

data[R]
expire_times[R]

Public Class Methods

new(base, *_args) click to toggle source
# File lib/mock_redis/database.rb, line 32
def initialize(base, *_args)
  @base = base
  @data = MockRedis::IndifferentHash.new
  @expire_times = []
end

Public Instance Methods

auth(_) click to toggle source

Redis commands go below this line and above 'private'

# File lib/mock_redis/database.rb, line 46
def auth(_)
  'OK'
end
bgrewriteaof() click to toggle source
# File lib/mock_redis/database.rb, line 50
def bgrewriteaof
  'Background append only file rewriting started'
end
bgsave() click to toggle source
# File lib/mock_redis/database.rb, line 54
def bgsave
  'Background saving started'
end
close()
Also aliased as: disconnect!
Alias for: disconnect
connected?() click to toggle source
# File lib/mock_redis/database.rb, line 64
def connected?
  true
end
dbsize() click to toggle source
# File lib/mock_redis/database.rb, line 68
def dbsize
  data.keys.length
end
del(*keys) click to toggle source
# File lib/mock_redis/database.rb, line 72
def del(*keys)
  keys = keys.flatten.map(&:to_s)
  assert_has_args(keys, 'del')

  keys.
    find_all { |key| data[key] }.
    each { |k| persist(k) }.
    each { |k| data.delete(k) }.
    length
end
Also aliased as: unlink
disconnect() click to toggle source
# File lib/mock_redis/database.rb, line 58
def disconnect
  nil
end
Also aliased as: close
disconnect!()
Alias for: close
dump(key) click to toggle source
# File lib/mock_redis/database.rb, line 134
def dump(key)
  value = data[key]
  value ? Marshal.dump(value) : nil
end
echo(msg) click to toggle source
# File lib/mock_redis/database.rb, line 84
def echo(msg)
  msg.to_s
end
eval(*args) click to toggle source
# File lib/mock_redis/database.rb, line 279
def eval(*args); end
evalsha(*args) click to toggle source
# File lib/mock_redis/database.rb, line 277
def evalsha(*args); end
exists(*keys) click to toggle source
# File lib/mock_redis/database.rb, line 120
def exists(*keys)
  keys.count { |key| data.key?(key) }
end
exists?(*keys) click to toggle source
# File lib/mock_redis/database.rb, line 124
def exists?(*keys)
  keys.each { |key| return true if data.key?(key) }
  false
end
expire(key, seconds) click to toggle source
# File lib/mock_redis/database.rb, line 88
def expire(key, seconds)
  pexpire(key, seconds.to_i * 1000)
end
expire_keys() click to toggle source

This method isn't private, but it also isn't a Redis command, so it doesn't belong up above with all the Redis commands.

# File lib/mock_redis/database.rb, line 360
def expire_keys
  now_sec, miliseconds = now
  now_ms = now_sec * 1_000 + miliseconds

  to_delete = expire_times.take_while do |(time, _key)|
    (time.to_r * 1_000).to_i <= now_ms
  end

  to_delete.each do |(_time, key)|
    del(key)
  end
end
expireat(key, timestamp) click to toggle source
# File lib/mock_redis/database.rb, line 98
def expireat(key, timestamp)
  unless looks_like_integer?(timestamp.to_s)
    raise Redis::CommandError, 'ERR value is not an integer or out of range'
  end

  pexpireat(key, timestamp.to_i * 1000)
end
flushdb() click to toggle source
# File lib/mock_redis/database.rb, line 129
def flushdb
  data.each_key { |k| del(k) }
  'OK'
end
initialize_copy(_source) click to toggle source
# File lib/mock_redis/database.rb, line 38
def initialize_copy(_source)
  @data = @data.clone
  @data.each_key { |k| @data[k] = @data[k].clone }
  @expire_times = @expire_times.map(&:clone)
end
keys(format = '*') click to toggle source
# File lib/mock_redis/database.rb, line 150
def keys(format = '*')
  data.keys.grep(redis_pattern_to_ruby_regex(format))
end
lastsave() click to toggle source
# File lib/mock_redis/database.rb, line 168
def lastsave
  now.first
end
now() click to toggle source
# File lib/mock_redis/database.rb, line 250
def now
  current_time = @base.options[:time_class].now
  miliseconds = (current_time.to_r - current_time.to_i) * 1_000
  [current_time.to_i, miliseconds.to_i]
end
Also aliased as: time
persist(key) click to toggle source
# File lib/mock_redis/database.rb, line 172
def persist(key)
  if exists?(key) && has_expiration?(key)
    remove_expiration(key)
    true
  else
    false
  end
end
pexpire(key, ms) click to toggle source
# File lib/mock_redis/database.rb, line 92
def pexpire(key, ms)
  now, miliseconds = @base.now
  now_ms = (now * 1000) + miliseconds
  pexpireat(key, now_ms + ms.to_i)
end
pexpireat(key, timestamp_ms) click to toggle source
# File lib/mock_redis/database.rb, line 106
def pexpireat(key, timestamp_ms)
  unless looks_like_integer?(timestamp_ms.to_s)
    raise Redis::CommandError, 'ERR value is not an integer or out of range'
  end

  if exists?(key)
    timestamp = Rational(timestamp_ms.to_i, 1000)
    set_expiration(key, @base.time_at(timestamp))
    true
  else
    false
  end
end
ping() click to toggle source
# File lib/mock_redis/database.rb, line 181
def ping
  'PONG'
end
pttl(key) click to toggle source
# File lib/mock_redis/database.rb, line 237
def pttl(key)
  now, miliseconds = @base.now
  now_ms = now * 1000 + miliseconds

  if !exists?(key)
    -2
  elsif has_expiration?(key)
    (expiration(key).to_r * 1000).to_i - now_ms
  else
    -1
  end
end
quit() click to toggle source
# File lib/mock_redis/database.rb, line 185
def quit
  'OK'
end
randomkey() click to toggle source
# File lib/mock_redis/database.rb, line 189
def randomkey
  data.keys[rand(data.length)]
end
rename(key, newkey) click to toggle source
# File lib/mock_redis/database.rb, line 193
def rename(key, newkey)
  unless data.include?(key)
    raise Redis::CommandError, 'ERR no such key'
  end

  if key != newkey
    data[newkey] = data.delete(key)
    if has_expiration?(key)
      set_expiration(newkey, expiration(key))
      remove_expiration(key)
    end
  end

  'OK'
end
renamenx(key, newkey) click to toggle source
# File lib/mock_redis/database.rb, line 209
def renamenx(key, newkey)
  unless data.include?(key)
    raise Redis::CommandError, 'ERR no such key'
  end

  if exists?(newkey)
    false
  else
    rename(key, newkey)
    true
  end
end
restore(key, ttl, value, replace: false) click to toggle source
# File lib/mock_redis/database.rb, line 139
def restore(key, ttl, value, replace: false)
  if !replace && exists?(key)
    raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
  end
  data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
  if ttl > 0
    pexpire(key, ttl)
  end
  'OK'
end
save() click to toggle source
# File lib/mock_redis/database.rb, line 222
def save
  'OK'
end
scan(cursor, opts = {}) click to toggle source
# File lib/mock_redis/database.rb, line 154
def scan(cursor, opts = {})
  common_scan(data.keys, cursor, opts)
end
scan_each(opts = {}, &block) click to toggle source
# File lib/mock_redis/database.rb, line 158
def scan_each(opts = {}, &block)
  return to_enum(:scan_each, opts) unless block_given?
  cursor = 0
  loop do
    cursor, keys = scan(cursor, opts)
    keys.each(&block)
    break if cursor == '0'
  end
end
script(subcommand, *args) click to toggle source
# File lib/mock_redis/database.rb, line 275
def script(subcommand, *args); end
time()
Alias for: now
ttl(key) click to toggle source
# File lib/mock_redis/database.rb, line 226
def ttl(key)
  if !exists?(key)
    -2
  elsif has_expiration?(key)
    now, = @base.now
    expiration(key).to_i - now
  else
    -1
  end
end
type(key) click to toggle source
# File lib/mock_redis/database.rb, line 257
def type(key)
  if !exists?(key)
    'none'
  elsif hashy?(key)
    'hash'
  elsif stringy?(key)
    'string'
  elsif listy?(key)
    'list'
  elsif sety?(key)
    'set'
  elsif zsety?(key)
    'zset'
  else
    raise ArgumentError, "Not sure how #{data[key].inspect} got in here"
  end
end

Private Instance Methods

assert_valid_timeout(timeout) click to toggle source
# File lib/mock_redis/database.rb, line 283
def assert_valid_timeout(timeout)
  if !looks_like_integer?(timeout.to_s)
    raise Redis::CommandError, 'ERR timeout is not an integer or out of range'
  elsif timeout < 0
    raise Redis::CommandError, 'ERR timeout is negative'
  end
  timeout
end
can_incr?(value) click to toggle source
# File lib/mock_redis/database.rb, line 292
def can_incr?(value)
  value.nil? || looks_like_integer?(value)
end
can_incr_float?(value) click to toggle source
# File lib/mock_redis/database.rb, line 296
def can_incr_float?(value)
  value.nil? || looks_like_float?(value)
end
expiration(key) click to toggle source
# File lib/mock_redis/database.rb, line 313
def expiration(key)
  expire_times.find { |(_, k)| k == key.to_s }.first
end
extract_timeout(arglist) click to toggle source
# File lib/mock_redis/database.rb, line 300
def extract_timeout(arglist)
  options = arglist.last
  if options.is_a?(Hash) && options[:timeout]
    timeout = assert_valid_timeout(options[:timeout])
    [arglist[0..-2], timeout]
  elsif options.is_a?(Integer)
    timeout = assert_valid_timeout(options)
    [arglist[0..-2], timeout]
  else
    [arglist, 0]
  end
end
has_expiration?(key) click to toggle source
# File lib/mock_redis/database.rb, line 317
def has_expiration?(key)
  expire_times.any? { |(_, k)| k == key.to_s }
end
looks_like_float?(str) click to toggle source
# File lib/mock_redis/database.rb, line 325
def looks_like_float?(str)
  !!Float(str) rescue false
end
looks_like_integer?(str) click to toggle source
# File lib/mock_redis/database.rb, line 321
def looks_like_integer?(str)
  str =~ /^-?\d+$/
end
redis_pattern_to_ruby_regex(pattern) click to toggle source
# File lib/mock_redis/database.rb, line 329
def redis_pattern_to_ruby_regex(pattern)
  Regexp.new(
    "^#{pattern}$".
    gsub(/([+|()])/, '\\\\\1').
    gsub(/(?<!\\)\?/, '\\1.').
    gsub(/([^\\])\*/, '\\1.*')
  )
end
remove_expiration(key) click to toggle source
# File lib/mock_redis/database.rb, line 338
def remove_expiration(key)
  expire_times.delete_if do |(_t, k)|
    key.to_s == k
  end
end
set_expiration(key, time) click to toggle source
# File lib/mock_redis/database.rb, line 344
def set_expiration(key, time)
  remove_expiration(key)
  found = expire_times.each_with_index.to_a.bsearch { |item, _| item.first >= time }
  index = found ? found.last : -1
  expire_times.insert(index, [time, key.to_s])
end
zero_pad(string, desired_length) click to toggle source
# File lib/mock_redis/database.rb, line 351
def zero_pad(string, desired_length)
  padding = "\000" * [(desired_length - string.length), 0].max
  string + padding
end