Module: IdentityCache::QueryAPI::ClassMethods

Defined in:
lib/identity_cache/query_api.rb

Instance Method Summary collapse

Instance Method Details

#exists_with_identity_cache?(id) ⇒ Boolean

Similar to ActiveRecord::Base#exists? will return true if the id can be found in the cache or in the DB.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


12
13
14
15
# File 'lib/identity_cache/query_api.rb', line 12

def exists_with_identity_cache?(id)
  raise NotImplementedError, "exists_with_identity_cache? needs the primary index enabled" unless primary_cache_index_enabled
  !!fetch_by_id(id)
end

#fetch(id, options = {}) ⇒ Object

Default fetcher added to the model on inclusion, it behaves like ActiveRecord::Base.find, will raise ActiveRecord::RecordNotFound exception if id is not in the cache or the db.



44
45
46
# File 'lib/identity_cache/query_api.rb', line 44

def fetch(id, options={})
  fetch_by_id(id, options) or raise(ActiveRecord::RecordNotFound, "Couldn't find #{self.name} with ID=#{id}")
end

#fetch_by_id(id, options = {}) ⇒ Object

Default fetcher added to the model on inclusion, it behaves like ActiveRecord::Base.where(id: id).first

Raises:

  • (NotImplementedError)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/identity_cache/query_api.rb', line 19

def fetch_by_id(id, options={})
  ensure_base_model
  raise_if_scoped
  raise NotImplementedError, "fetching needs the primary index enabled" unless primary_cache_index_enabled
  return unless id
  record = if should_use_cache?
    require_if_necessary do
      object = nil
      coder = IdentityCache.fetch(rails_cache_key(id)){ coder_from_record(object = resolve_cache_miss(id)) }
      object ||= record_from_coder(coder)
      if object && object.id.to_s != id.to_s
        IdentityCache.logger.error "[IDC id mismatch] fetch_by_id_requested=#{id} fetch_by_id_got=#{object.id} for #{object.inspect[(0..100)]}"
      end
      object
    end
  else
    resolve_cache_miss(id)
  end
  prefetch_associations(options[:includes], [record]) if record && options[:includes]
  record
end

#fetch_multi(*ids) ⇒ Object

Default fetcher added to the model on inclusion, if behaves like ActiveRecord::Base.find_all_by_id

Raises:

  • (NotImplementedError)


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/identity_cache/query_api.rb', line 50

def fetch_multi(*ids)
  ensure_base_model
  raise_if_scoped
  raise NotImplementedError, "fetching needs the primary index enabled" unless primary_cache_index_enabled
  options = ids.extract_options!
  ids.flatten!(1)
  records = if should_use_cache?
    require_if_necessary do
      cache_keys = ids.map {|id| rails_cache_key(id) }
      key_to_id_map = Hash[ cache_keys.zip(ids) ]
      key_to_record_map = {}

      coders_by_key = IdentityCache.fetch_multi(cache_keys) do |unresolved_keys|
        ids = unresolved_keys.map {|key| key_to_id_map[key] }
        records = find_batch(ids)
        key_to_record_map = records.compact.index_by{ |record| rails_cache_key(record.id) }
        records.map {|record| coder_from_record(record) }
      end

      cache_keys.map{ |key| key_to_record_map[key] || record_from_coder(coders_by_key[key]) }
    end
  else
    find_batch(ids)
  end
  records.compact!
  prefetch_associations(options[:includes], records) if options[:includes]
  records
end

#prefetch_associations(associations, records) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/identity_cache/query_api.rb', line 79

def prefetch_associations(associations, records)
  records = records.to_a
  return if records.empty?

  case associations
  when nil
    # do nothing
  when Symbol
    prefetch_one_association(associations, records)
  when Array
    associations.each do |association|
      prefetch_associations(association, records)
    end
  when Hash
    associations.each do |association, sub_associations|
      next_level_records = prefetch_one_association(association, records)

      if sub_associations.present?
        associated_class = reflect_on_association(association).klass
        associated_class.prefetch_associations(sub_associations, next_level_records)
      end
    end
  else
    raise TypeError, "Invalid associations class #{associations.class}"
  end
  nil
end