class Tally::KeyFinder

Locates keys for a given day, key, and/or record

Attributes

key[R]
record[R]
type[R]

Public Class Methods

find(*args) click to toggle source
# File lib/tally/key_finder.rb, line 64
def self.find(*args)
  new(*args).entries
end
new(key: nil, day: nil, record: nil, type: nil) click to toggle source
# File lib/tally/key_finder.rb, line 13
def initialize(key: nil, day: nil, record: nil, type: nil)
  @key = key.to_s.gsub(":", ".").downcase.strip if key.present?
  @day = day
  @record = record
  @type = type unless record.present?

  @day = @day.to_date if Time === @day
end

Public Instance Methods

day() click to toggle source
# File lib/tally/key_finder.rb, line 22
def day
  @day ||= Time.current.utc.to_date
end
entries() click to toggle source
# File lib/tally/key_finder.rb, line 26
def entries
  @entries ||= all_keys.map do |key|
    if match = key.match(entry_regex)
      Entry.new(match, key, day)
    end
  end.compact
end
keys() click to toggle source
# File lib/tally/key_finder.rb, line 34
def keys
  entries.map(&:key).compact.uniq
end
raw_keys() click to toggle source
# File lib/tally/key_finder.rb, line 38
def raw_keys
  all_keys
end
records() click to toggle source

load up all records for the given keys, tries to batch them by model type so there's not an N+1 here

# File lib/tally/key_finder.rb, line 44
def records
  models = entries.reduce({}) do |result, entry|
    result[entry.type] ||= []
    result[entry.type].push(entry.id)
    result
  end

  models.map do |model, ids|
    next unless ids.compact.any?

    if klass = model.to_s.classify.safe_constantize
      klass.where(id: ids)
    end
  end.compact.flatten
end
types() click to toggle source
# File lib/tally/key_finder.rb, line 60
def types
  entries.map(&:type).compact.uniq
end

Private Instance Methods

all_keys() click to toggle source
# File lib/tally/key_finder.rb, line 70
def all_keys
  @keys ||= build_keys_from_redis
end
build_keys_from_redis() click to toggle source
# File lib/tally/key_finder.rb, line 74
def build_keys_from_redis
  result = []
  cursor = ""

  scan = scan_from_redis

  while cursor != "0"
    result << scan.last
    cursor = scan.first

    scan = scan_from_redis(cursor: cursor)
  end

  result.flatten
end
day_key() click to toggle source
# File lib/tally/key_finder.rb, line 90
def day_key
  @day_key ||= if day == "*"
    "*"
  else
    day.strftime(Tally.config.date_format)
  end
end
entry_regex() click to toggle source
# File lib/tally/key_finder.rb, line 98
def entry_regex
  @entry_regex ||= Regexp.new("#{ Tally.config.prefix }:?(?<record>[^:]+:[\\d]+)?:?(?<key>[^:]+)?@")
end
scan_from_redis(cursor: "0") click to toggle source
# File lib/tally/key_finder.rb, line 102
def scan_from_redis(cursor: "0")
  Tally.redis { |conn| conn.scan(cursor, match: scan_key) }
end
scan_key() click to toggle source
# File lib/tally/key_finder.rb, line 106
def scan_key
  @scan_key ||= if key.present? && record.present?
    "#{ Tally.config.prefix }:#{ record.model_name.i18n_key }:#{ record.id }:#{ key }@#{ day_key }"
  elsif key.present? && type.present?
    "#{ Tally.config.prefix }:#{ type }:*:#{ key }@#{ day_key }"
  elsif record.present?
    "#{ Tally.config.prefix }:#{ record.model_name.i18n_key }:#{ record.id }:*@#{ day_key }"
  elsif type.present?
    "#{ Tally.config.prefix }:#{ type }:*:*@#{ day_key }"
  elsif key.present?
    "#{ Tally.config.prefix }:*#{ key }@#{ day_key }"
  else
    "#{ Tally.config.prefix }*@#{ day_key }"
  end
end