# File lib/lookup_by/cache.rb, line 158 def primary_key?(value) case @primary_key_type when :integer value.is_a? Integer when :uuid, :string value =~ UUID_REGEX end end
class LookupBy::Cache
Attributes
cache[R]
field[R]
reverse[R]
stats[R]
testing[RW]
Public Class Methods
new(klass, options = {})
click to toggle source
# File lib/lookup_by/cache.rb, line 7 def initialize(klass, options = {}) @klass = klass @primary_key = klass.primary_key @primary_key_type = klass.columns_hash[@primary_key].type @field = options[:field].to_sym @cache = {} @reverse = {} @order = options[:order] || @field @read = options[:find_or_create] || options[:find] @write = options[:find_or_create] @allow_blank = options[:allow_blank] || false @normalize = options[:normalize] @raise_on_miss = options[:raise] || false @testing = false @enabled = true @safe = options.fetch(:safe, true) @mutex = Mutex.new if @safe @stats = { db: Hash.new(0), cache: Hash.new(0) } raise ArgumentError, %Q(unknown attribute "#{@field}" for <#{klass}>) unless klass.column_names.include?(@field.to_s) # Order matters here, some instance variables depend on prior assignments. case options[:cache] when true @type = :all @read ||= false raise ArgumentError, "`#{@klass}.lookup_by :#{@field}` Should be `cache: true` or `cache: N, find_or_create: true`" if @write when ::Integer raise ArgumentError, "`#{@klass}.lookup_by :#{@field}` options[:find] must be true when caching N" if @read == false @type = :lru @limit = options[:cache] @cache = @safe ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit) @reverse = @safe ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit) @read = true @write ||= false @testing = true if Rails.env.test? && @write else @read = true end if @write && @raise_on_miss raise ArgumentError, "`#{@klass}.lookup_by :#{@field}` can not use `raise: true` and `find_or_create: true` together." end end
Public Instance Methods
allow_blank?()
click to toggle source
# File lib/lookup_by/cache.rb, line 120 def allow_blank? @allow_blank end
clear()
click to toggle source
# File lib/lookup_by/cache.rb, line 70 def clear @cache.clear @reverse.clear end
create(*args, &block)
click to toggle source
# File lib/lookup_by/cache.rb, line 75 def create(*args, &block) @klass.create(*args, &block).tap do |created| cache_write(created) if cache? end end
create!(*args, &block)
click to toggle source
# File lib/lookup_by/cache.rb, line 81 def create!(*args, &block) @klass.create!(*args, &block).tap do |created| cache_write(created) if cache? end end
disable!()
click to toggle source
# File lib/lookup_by/cache.rb, line 139 def disable! return if disabled? @enabled = false clear end
disabled?()
click to toggle source
# File lib/lookup_by/cache.rb, line 128 def disabled? !@enabled end
enable!()
click to toggle source
# File lib/lookup_by/cache.rb, line 132 def enable! return if enabled? @enabled = true reload end
enabled?()
click to toggle source
# File lib/lookup_by/cache.rb, line 124 def enabled? @enabled end
fetch(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 93 def fetch(value) increment :cache, :get value = normalize(value) if @normalize && !primary_key?(value) found = cache_read(value) if cache? found ||= db_read(value) if @read || !@enabled cache_write(found) if cache? found ||= db_write(value) if @write if @raise_on_miss && found.nil? raise LookupBy::RecordNotFound, "No #{@klass.name} lookup record found for value: #{value.inspect}" end found end
has_cache?()
click to toggle source
# File lib/lookup_by/cache.rb, line 112 def has_cache? @type && @enabled end
load()
click to toggle source
# File lib/lookup_by/cache.rb, line 55 def load return unless @type == :all ::ActiveRecord::Base.connection.send :log, "", "#{@klass.name} Load Cache All" do @klass.order(@order).readonly.each do |object| cache_write(object) end end end
read_through?()
click to toggle source
# File lib/lookup_by/cache.rb, line 116 def read_through? @read end
reload()
click to toggle source
# File lib/lookup_by/cache.rb, line 65 def reload clear load end
seed(*values)
click to toggle source
# File lib/lookup_by/cache.rb, line 87 def seed(*values) @klass.transaction(requires_new: true) do values.map { |value| @klass.where(@field => value).first_or_create! } end end
while_disabled() { || ... }
click to toggle source
# File lib/lookup_by/cache.rb, line 146 def while_disabled raise ArgumentError, "no block given" unless block_given? disable! yield enable! end
Private Instance Methods
cache?()
click to toggle source
# File lib/lookup_by/cache.rb, line 241 def cache? @type && @enabled && !@testing end
cache_read(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 172 def cache_read(value) if primary_key?(value) @cache[value] else @reverse[value] end end
cache_write(object)
click to toggle source
# File lib/lookup_by/cache.rb, line 210 def cache_write(object) return unless object @mutex.synchronize do @reverse[object.send(@field).to_s] = @cache[object.id] = object end end
column_for(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 237 def column_for(value) primary_key?(value) ? @primary_key : @field end
db_read(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 194 def db_read(value) @klass.where(column_for(value) => value).first end
db_write(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 225 def db_write(value) column = column_for(value) return if column == @primary_key @klass.transaction(requires_new: true) do @klass.create(column => value) end rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation db_read(value) end
increment(type, stat)
click to toggle source
# File lib/lookup_by/cache.rb, line 245 def increment(type, stat) @stats[type][stat] += 1 end
normalize(value)
click to toggle source
# File lib/lookup_by/cache.rb, line 167 def normalize(value) @klass.new(@field => value).send(@field) end
primary_key?(value)
click to toggle source