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.



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

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] || 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

#cacheObject (readonly)

Returns the value of attribute cache.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def cache
  @cache
end

#expiryObject (readonly)

Returns the value of attribute expiry.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def expiry
  @expiry
end

#fieldsObject (readonly)

Returns the value of attribute fields.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def fields
  @fields
end

#index_fieldObject (readonly)

Returns the value of attribute index_field.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def index_field
  @index_field
end

#limitObject (readonly)

Returns the value of attribute limit.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def limit
  @limit
end

#model_classObject (readonly)

Returns the value of attribute model_class.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def model_class
  @model_class
end

#nameObject (readonly)

Returns the value of attribute name.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def name
  @name
end

#order_byObject (readonly)

Returns the value of attribute order_by.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def order_by
  @order_by
end

#prefixObject (readonly)

Returns the value of attribute prefix.



5
6
7
# File 'lib/record_cache/index.rb', line 5

def prefix
  @prefix
end

Class Method Details

.disable_dbObject



208
209
210
# File 'lib/record_cache/index.rb', line 208

def self.disable_db
  @@disable_db = true
end

.enable_dbObject



212
213
214
# File 'lib/record_cache/index.rb', line 212

def self.enable_db
  @@disable_db = false
end

Instance Method Details

#auto_name?Boolean

Returns:

  • (Boolean)


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

def auto_name?;     @auto_name;     end

#cached_set(id) ⇒ Object



235
236
237
238
239
240
241
# File 'lib/record_cache/index.rb', line 235

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)


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

def disallow_null?; @disallow_null; end

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



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/record_cache/index.rb', line 127

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 = [].to_ordered_set
  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.to_a
  else
    field_by_index
  end
end

#fields_hashObject



49
50
51
52
53
54
55
56
57
58
# File 'lib/record_cache/index.rb', line 49

def fields_hash
  if @fields_hash.nil?
    if full_record?
      @fields_hash ||= model_class.column_names.hash
    else
      @fields_hash ||= fields.collect {|field| field.to_s}.hash
    end
  end
  @fields_hash
end

#find_by_field(keys, model_class, type) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/record_cache/index.rb', line 94

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



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/record_cache/index.rb', line 60

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



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/record_cache/index.rb', line 216

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)


33
34
35
# File 'lib/record_cache/index.rb', line 33

def full_record?
  fields.empty?
end

#includes_id?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/record_cache/index.rb', line 37

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

#invalidate(*keys) ⇒ Object



154
155
156
157
158
159
160
161
# File 'lib/record_cache/index.rb', line 154

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

#invalidate_from_conditions(conditions) ⇒ Object



170
171
172
# File 'lib/record_cache/index.rb', line 170

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

#invalidate_from_conditions_lambda(conditions) ⇒ Object



163
164
165
166
167
168
# File 'lib/record_cache/index.rb', line 163

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



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/record_cache/index.rb', line 174

def invalidate_model(model)
  attribute     = model.send(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



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

def namespace
  "#{model_class.name}_#{model_class.version}_#{RecordCache.version}:#{name}" << ( full_record? ? '' : ":#{fields.join(',')}" )
end

#scopeObject



203
204
205
# File 'lib/record_cache/index.rb', line 203

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

#scope_queryObject



198
199
200
201
# File 'lib/record_cache/index.rb', line 198

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

#set_classObject



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

def set_class
  @set_class.constantize
end

#write_ahead?Boolean

Returns:

  • (Boolean)


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

def write_ahead?;   @write_ahead;   end