Class: Scrooge::Optimizations::ResultSets::UpdateableResultSet

Inherits:
Object
  • Object
show all
Defined in:
lib/optimizations/result_sets/updateable_result_set.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(result_set_array, klass) ⇒ UpdateableResultSet

Returns a new instance of UpdateableResultSet.



11
12
13
14
15
16
17
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 11

def initialize(result_set_array, klass)
  if result_set_array
    @result_set_object_id = result_set_array.object_id
    @unique_id = result_set_array.unique_id ||= "#{Time.now.to_f}#{object_id}"  # avoid recycled object ids
  end
  @klass = klass  # expected class of items in the array
end

Instance Attribute Details

#updaters_attributesObject

Contains a weak referernce to the result set, and can update from DB



9
10
11
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 9

def updaters_attributes
  @updaters_attributes
end

Instance Method Details

#default_attributesObject

When called from after_find and after_initialize, the object being accessed (and causing the reload) is not in the result set yet. We make sure that we add its attributes to result_set_attributes so it gets reloaded too



63
64
65
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 63

def default_attributes
  [@updaters_attributes]
end

#hash_by_primary_key(rows) ⇒ Object

Make an efficient data structure to access items when the primary key is known



94
95
96
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 94

def hash_by_primary_key(rows)
  rows.inject({}) {|memo, row| memo[row[primary_key_name]] = row; memo}
end

#primary_key_nameObject



98
99
100
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 98

def primary_key_name
  @klass.primary_key
end

#reload_columns!(columns_to_fetch) ⇒ Object

Called by a ScroogedAttributes hash when it is asked for a column that was not fetched from the DB



22
23
24
25
26
27
28
29
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 22

def reload_columns!(columns_to_fetch)
  reloaded_columns = hash_by_primary_key(reload_columns_for_ids(columns_to_fetch, result_set_ids))
  if !reloaded_columns.has_key?(@updaters_attributes[primary_key_name])
    raise ActiveRecord::MissingAttributeError, "scrooge cannot fetch missing attribute(s) #{columns_to_fetch.to_a.join(', ')} because record went away"
  else
    update_with(reloaded_columns)
  end
end

#reload_columns_for_ids(columns_to_fetch, result_ids_to_fetch) ⇒ Object



31
32
33
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 31

def reload_columns_for_ids(columns_to_fetch, result_ids_to_fetch)
  @klass.scrooge_reload(result_ids_to_fetch, columns_to_fetch + [primary_key_name])
end

#result_setObject

The result set is weak referenced by its object_id So we check that a unique id matches what we have remembered to make sure that we got the right object (object ids are recycled by ruby)



50
51
52
53
54
55
56
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 50

def result_set
  return nil unless @result_set_object_id
  result_set = ObjectSpace._id2ref(@result_set_object_id)
  result_set.is_a?(ResultArray) && result_set.unique_id == @unique_id ? result_set : nil
rescue RangeError
  nil
end

#result_set_attributesObject



35
36
37
38
39
40
41
42
43
44
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 35

def result_set_attributes
  rs = result_set
  return default_attributes unless rs
  rs.inject(default_attributes) do |memo, r|
    if r.is_a?(@klass)
      memo << r.instance_variable_get(:@attributes)
    end
    memo
  end.uniq
end

#result_set_idsObject

Ids of the items to be reloaded



69
70
71
72
73
74
75
76
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 69

def result_set_ids
  result_set_attributes.inject([]) do |memo, attributes|
    unless attributes.fully_fetched
      memo << attributes[primary_key_name]
    end
    memo
  end
end

#update_with(remaining_attributes) ⇒ Object

Update the result set with attributes provided, as returned by the sql server



81
82
83
84
85
86
87
88
89
# File 'lib/optimizations/result_sets/updateable_result_set.rb', line 81

def update_with(remaining_attributes)
  current_attributes = hash_by_primary_key(result_set_attributes)
  remaining_attributes.each do |r_id, r_att|
    old_attributes = current_attributes[r_id]
    if old_attributes
      old_attributes.update(r_att.merge(old_attributes)) # must call update, do not use reverse_update
    end
  end
end