diff options
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/attribute_set/builder.rb | 21 | ||||
-rw-r--r-- | activerecord/lib/active_record/inheritance.rb | 12 | ||||
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 28 | ||||
-rw-r--r-- | activerecord/lib/active_record/querying.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/result.rb | 9 |
5 files changed, 61 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb index d4a787f2fe..0a62c68bfb 100644 --- a/activerecord/lib/active_record/attribute_set/builder.rb +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -8,18 +8,33 @@ module ActiveRecord end def build_from_database(values = {}, additional_types = {}) - attributes = build_attributes_from_values(values, additional_types) + build_from_database_pairs(values.keys, values.values, additional_types) + end + + def build_from_database_pairs(columns, values, additional_types) + attributes = build_attributes_from_values(columns, values, additional_types) add_uninitialized_attributes(attributes) AttributeSet.new(attributes) end private - def build_attributes_from_values(values, additional_types) - values.each_with_object({}) do |(name, value), hash| + def build_attributes_from_values(columns, values, additional_types) + # We are performing manual iteration here as this method is a performance + # hotspot + hash = {} + index = 0 + length = columns.length + + while index < length + name = columns[index] + value = values[index] type = additional_types.fetch(name, types[name]) hash[name] = Attribute.from_database(name, value, type) + index += 1 end + + hash end def add_uninitialized_attributes(attributes) diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index f58145ab05..4aad3217cb 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -165,15 +165,19 @@ module ActiveRecord # record instance. For single-table inheritance, we check the record # for a +type+ column and return the corresponding class. def discriminate_class_for_record(record) - if using_single_table_inheritance?(record) - find_sti_class(record[inheritance_column]) + discriminate_class_for_value(record[inheritance_column]) + end + + def discriminate_class_for_value(value) + if using_single_table_inheritance?(value) + find_sti_class(value) else super end end - def using_single_table_inheritance?(record) - record[inheritance_column].present? && columns_hash.include?(inheritance_column) + def using_single_table_inheritance?(value) + value.present? && columns_hash.include?(inheritance_column) end def find_sti_class(type_name) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 755ff2b2f1..9d2c9d3b9c 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -65,19 +65,41 @@ module ActiveRecord # how this "single-table" inheritance mapping is implemented. def instantiate(attributes, column_types = {}) klass = discriminate_class_for_record(attributes) - attributes = klass.attributes_builder.build_from_database(attributes, column_types) - klass.allocate.init_with('attributes' => attributes, 'new_record' => false) + klass.instantiate_pairs(attributes.keys, attributes.values, column_types) + end + + def instantiate_pairs(columns, values, column_types = {}) # :nodoc: + attributes = attributes_builder.build_from_database_pairs(columns, values, column_types) + allocate.init_with('attributes' => attributes, 'new_record' => false) + end + + def instantiate_result_set(result_set, column_types = {}) # :nodoc: + inheritance_column_index = inheritance_column && result_set.columns.find_index(inheritance_column) + + result_set.each_pair.map do |columns, values| + inheritance_value = inheritance_column_index && values[inheritance_column_index] + klass = discriminate_class_for_value(inheritance_value) + klass.instantiate_pairs(columns, values, column_types) + end end private # Called by +instantiate+ to decide which class to use for a new # record instance. # - # See +ActiveRecord::Inheritance#discriminate_class_for_record+ for + # See +ActiveRecord::Inheritance#discriminate_class_for_value+ for # the single-table inheritance discriminator. + def discriminate_class_for_value(*) + self + end + def discriminate_class_for_record(record) self end + + def inheritance_column + nil + end end # Returns true if this object hasn't been saved yet -- that is, a record diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb index e8de4db3a7..9d4df81b07 100644 --- a/activerecord/lib/active_record/querying.rb +++ b/activerecord/lib/active_record/querying.rb @@ -47,7 +47,7 @@ module ActiveRecord } message_bus.instrument('instantiation.active_record', payload) do - result_set.map { |record| instantiate(record, column_types) } + instantiate_result_set(result_set, column_types) end end diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb index 3a3e65ef32..c84ad586e2 100644 --- a/activerecord/lib/active_record/result.rb +++ b/activerecord/lib/active_record/result.rb @@ -54,6 +54,15 @@ module ActiveRecord end end + def each_pair + return to_enum(__method__) unless block_given? + + columns = @columns.map { |c| c.dup.freeze } + @rows.each do |row| + yield columns, row + end + end + def to_hash hash_rows end |