Class: RecordCache::Index

Inherits:
Object
  • Object
show all
Includes:
Deferrable
Defined in:
lib/record_cache/index.rb

Constant Summary collapse

NULL =
'NULL'
@@disable_db =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Index

Returns a new instance of Index.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/record_cache/index.rb', line 11

def initialize(opts)
  raise ':by => index_field required for cache'       if opts[:by].nil?
  raise 'explicit name or prefix required with scope' if opts[:scope] and opts[:name].nil? and opts[:prefix].nil?

  @auto_name     = opts[:name].nil?
  @write_ahead   = opts[:write_ahead]
  @cache         = opts[:cache].kind_of?(Symbol) ? Memcache.pool[opts[:cache]] : (opts[:cache] || CACHE)
  @expiry        = opts[:expiry]
  @model_class   = opts[:class]
  @set_class     = opts[:set_class] || "#{@model_class}Set"
  @index_field   = opts[:by].to_s
  @fields        = opts[:fields].collect {|field| field.to_s}
  @prefix        = opts[:prefix]
  @name          = ( opts[:name] || [prefix, 'by', index_field].compact.join('_') ).to_s
  @order_by      = opts[:order_by]
  @limit         = opts[:limit]
  @disallow_null = opts[:null] == false
  @scope_query   = opts[:scope] || {}
end

Instance Attribute Details

#expiryObject (readonly)

Returns the value of attribute expiry.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def expiry
  @expiry
end

#fieldsObject (readonly)

Returns the value of attribute fields.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def fields
  @fields
end

#index_fieldObject (readonly)

Returns the value of attribute index_field.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def index_field
  @index_field
end

#limitObject (readonly)

Returns the value of attribute limit.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def limit
  @limit
end

#model_classObject (readonly)

Returns the value of attribute model_class.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def model_class
  @model_class
end

#nameObject (readonly)

Returns the value of attribute name.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def name
  @name
end

#order_byObject (readonly)

Returns the value of attribute order_by.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def order_by
  @order_by
end

#prefixObject (readonly)

Returns the value of attribute prefix.



7
8
9
# File 'lib/record_cache/index.rb', line 7

def prefix
  @prefix
end

Class Method Details

.disable_dbObject



224
225
226
# File 'lib/record_cache/index.rb', line 224

def self.disable_db
  @@disable_db = true
end

.enable_dbObject



228
229
230
# File 'lib/record_cache/index.rb', line 228

def self.enable_db
  @@disable_db = false
end

Instance Method Details

#auto_name?Boolean

Returns:

  • (Boolean)


43
# File 'lib/record_cache/index.rb', line 43

def auto_name?;     @auto_name;     end

#cacheObject



35
36
37
38
39
40
41
# File 'lib/record_cache/index.rb', line 35

def cache
  if RecordCache.config[:thread_safe]
    Thread.current[:record_cache] ||= @cache.clone
  else
    @cache
  end
end

#cached_set(id) ⇒ Object



251
252
253
254
255
256
257
# File 'lib/record_cache/index.rb', line 251

def cached_set(id)
  # Used for debugging. Gives you the RecordCache::Set that is currently in the cache.
  id = stringify([id]).first
  cache.in_namespace(namespace) do
    cache.get(id)
  end
end

#disallow_null?Boolean

Returns:

  • (Boolean)


45
# File 'lib/record_cache/index.rb', line 45

def disallow_null?; @disallow_null; end

#field_lookup(keys, model_class, field, flag = nil) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/record_cache/index.rb', line 141

def field_lookup(keys, model_class, field, flag = nil)
  keys = [*keys]
  keys = stringify(keys)
  field = field.to_s if field
  records_by_key = get_records(keys)

  field_by_index = {}
  all_fields = []
  keys.each do |key|
    records = records_by_key[key]
    fields = field ? records.fields(field, model_class) : records.all_fields(model_class, :except => index_field)
    if flag == :all
      all_fields.concat(fields)
    elsif flag == :first
      next if fields.empty?
      field_by_index[index_column.type_cast(key)] = fields.first
    else
      field_by_index[index_column.type_cast(key)] = fields
    end
  end
  if flag == :all
    all_fields.uniq
  else
    field_by_index
  end
end

#fields_hashObject



64
65
66
67
68
69
70
71
72
# File 'lib/record_cache/index.rb', line 64

def fields_hash
  if @fields_hash.nil?
    fields = full_record? ? model_class.column_names : self.fields
    md5 = Digest::MD5::new
    md5 << fields.sort.join(',')
    @fields_hash = md5.hexdigest
  end
  @fields_hash
end

#find_by_field(keys, model_class, type) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/record_cache/index.rb', line 108

def find_by_field(keys, model_class, type)
  keys = [keys] if not keys.kind_of?(Array)
  keys = stringify(keys)
  records_by_key = get_records(keys)

  case type
  when :first
    keys.each do |key|
      model = records_by_key[key].instantiate_first(model_class, full_record?)
      return model if model
    end
    return nil
  when :all
    models = []
    keys.each do |key|
      models.concat( records_by_key[key].instantiate(model_class, full_record?) )
    end
    models
  when :set, :ids
    ids = []
    keys.each do |key|
      ids.concat( records_by_key[key].ids(model_class) )
    end
    type == :set ? set_class.new(ids) : ids
  when :raw
    raw_records = []
    keys.each do |key|
      raw_records.concat( records_by_key[key].records(model_class) )
    end
    raw_records
  end
end

#find_by_ids(ids, model_class) ⇒ Object



74
75
76
77
78
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
106
# File 'lib/record_cache/index.rb', line 74

def find_by_ids(ids, model_class)
  expects_array = ids.first.kind_of?(Array)
  ids = ids.flatten.compact.collect {|id| id.to_i}
  ids = stringify(ids)

  if ids.empty?
    return [] if expects_array
    raise ActiveRecord::RecordNotFound, "Couldn't find #{model_class} without an ID"
  end

  records_by_id = get_records(ids)

  models = ids.collect do |id|
    records = records_by_id[id]
    model   = records.instantiate_first(model_class, full_record?) if records

    # try to get record from db again before we throw an exception
    if model.nil?
      invalidate(id)
      records = get_records([id])[id]
      model   = records.instantiate_first(model_class, full_record?) if records
    end

    raise ActiveRecord::RecordNotFound, "Couldn't find #{model_class} with ID #{id}" unless model
    model
  end

  if models.size == 1 and not expects_array
    models.first
  else
    models
  end
end

#find_method_name(type) ⇒ Object



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/record_cache/index.rb', line 232

def find_method_name(type)
  if name =~ /(^|_)by_/
    if type == :first
      "find_#{name}"
    else
      "find_#{type}_#{name}"
    end
  else
    case type
    when :all
      "find_#{name}"
    when :first
      "find_#{type}_#{name.singularize}"
    else
      "find_#{name.singularize}_#{type}"
    end
  end
end

#full_record?Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/record_cache/index.rb', line 47

def full_record?
  fields.empty?
end

#includes_id?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/record_cache/index.rb', line 51

def includes_id?
  full_record? or fields.include?('id')
end

#invalidate(*keys) ⇒ Object



168
169
170
171
172
173
174
175
176
177
# File 'lib/record_cache/index.rb', line 168

def invalidate(*keys)
  return if model_class.record_cache_config[:disable_write]

  keys = stringify(keys)
  cache.in_namespace(namespace) do
    keys.each do |key|
      cache.delete(key)
    end
  end
end

#invalidate_from_conditions(conditions) ⇒ Object



186
187
188
# File 'lib/record_cache/index.rb', line 186

def invalidate_from_conditions(conditions)
  invalidate_from_conditions_lambda(conditions).call
end

#invalidate_from_conditions_lambda(conditions) ⇒ Object



179
180
181
182
183
184
# File 'lib/record_cache/index.rb', line 179

def invalidate_from_conditions_lambda(conditions)
  sql = "SELECT #{index_field} FROM #{table_name} "
  model_class.send(:add_conditions!, sql, conditions, model_class.send(:scope, :find))
  ids = db.select_values(sql)
  lambda { invalidate(*ids) }
end

#invalidate_model(model) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/record_cache/index.rb', line 190

def invalidate_model(model)
  attribute     = model.read_attribute(index_field)
  attribute_was = model.attr_was(index_field)
  if scope.match_previous?(model)
    if write_ahead?
      remove_from_cache(model)
    else
      now_and_later do
        invalidate(attribute_was)
      end
    end
  end

  if scope.match_current?(model)
    if write_ahead?
      add_to_cache(model)
    elsif not (scope.match_previous?(model) and attribute_was == attribute)
      now_and_later do
        invalidate(attribute)
      end
    end
  end
end

#namespaceObject



59
60
61
62
# File 'lib/record_cache/index.rb', line 59

def namespace
  record_cache_class = model_class.record_cache_class
  "#{record_cache_class.name}_#{record_cache_class.version}_#{RecordCache.version}_#{fields_hash}:#{name}"
end

#scopeObject



219
220
221
# File 'lib/record_cache/index.rb', line 219

def scope
  @scope ||= Scope.new(model_class, scope_query)
end

#scope_queryObject



214
215
216
217
# File 'lib/record_cache/index.rb', line 214

def scope_query
  @scope_query[:type] ||= model_class.to_s if sub_class?
  @scope_query
end

#set_classObject



55
56
57
# File 'lib/record_cache/index.rb', line 55

def set_class
  @set_class.constantize
end

#to_sObject



31
32
33
# File 'lib/record_cache/index.rb', line 31

def to_s
  "<RecordCache::Index #{@model_class} by #{@index_field} (#{@name})>"
end

#write_ahead?Boolean

Returns:

  • (Boolean)


44
# File 'lib/record_cache/index.rb', line 44

def write_ahead?;   @write_ahead;   end