Skip to content

Commit

Permalink
Speeded up eager loading a whole bunch
Browse files Browse the repository at this point in the history
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1212 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Apr 18, 2005
1 parent 3b9bf64 commit 49d0f0c
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 52 deletions.
88 changes: 38 additions & 50 deletions activerecord/lib/active_record/associations.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -683,34 +683,42 @@ def find_with_associations(options = {})
schema_abbreviations = generate_schema_abbreviations(reflections) schema_abbreviations = generate_schema_abbreviations(reflections)
primary_key_table = generate_primary_key_table(reflections, schema_abbreviations) primary_key_table = generate_primary_key_table(reflections, schema_abbreviations)


rows = select_all_rows(options, schema_abbreviations, reflections) rows = select_all_rows(options, schema_abbreviations, reflections)
records = extract_and_instantiate_records(schema_abbreviations, rows) records = { }

primary_key = primary_key_table[table_name]
assign_associations_to_records(rows, records, reflections, schema_abbreviations, primary_key_table)
for row in rows
id = row[primary_key]
records[id] ||= instantiate(extract_record(schema_abbreviations, table_name, row))


return records
end

def assign_associations_to_records(rows, records, reflections, schema_abbreviations, primary_key_table)
records.each do |record|
reflections.each do |reflection| reflections.each do |reflection|
next unless row[primary_key_table[reflection.table_name]]

case reflection.macro case reflection.macro
when :has_many, :has_and_belongs_to_many when :has_many, :has_and_belongs_to_many
record.send(reflection.name).target = records[id].send(reflection.name)
extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection) records[id].instance_variable_get("@#{reflection.name}").target.push(
reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
)
when :has_one, :belongs_to when :has_one, :belongs_to
record.send( records[id].send(
"set_#{reflection.name}_target", "#{reflection.name}=",
extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection).first reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
) )
end end
end end
end end

return records.values
end end


def reflect_on_included_associations(associations)
[ associations ].flatten.collect { |association| reflect_on_association(association) }
end

def generate_schema_abbreviations(reflections) def generate_schema_abbreviations(reflections)
schema = [ [ table_name, columns.collect { |c| c.name } ] ] schema = [ [ table_name, column_names ] ]
schema += reflections.collect { |r| [ r.klass.table_name, r.klass.columns.collect { |c| c.name } ] } schema += reflections.collect { |r| [ r.table_name, r.klass.column_names ] }


schema_abbreviations = {} schema_abbreviations = {}
schema.each_with_index do |table_and_columns, i| schema.each_with_index do |table_and_columns, i|
Expand All @@ -736,9 +744,14 @@ def generate_primary_key_table(reflections, schema_abbreviations)
end end




def construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections) def select_all_rows(options, schema_abbreviations, reflections)
habtm_associations = reflections.find_all { |r| r.macro == :has_and_belongs_to_many } connection.select_all(
construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections),
"#{name} Load Including Associations"
)
end


def construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections)
sql = "SELECT #{column_aliases(schema_abbreviations)} FROM #{table_name} " sql = "SELECT #{column_aliases(schema_abbreviations)} FROM #{table_name} "
sql << reflections.collect { |reflection| association_join(reflection) }.to_s sql << reflections.collect { |reflection| association_join(reflection) }.to_s
sql << "#{options[:joins]} " if options[:joins] sql << "#{options[:joins]} " if options[:joins]
Expand Down Expand Up @@ -775,39 +788,14 @@ def association_join(reflection)
end end




def extract_and_instantiate_records(schema_abbreviations, rows)
rows.collect { |row| instantiate(extract_record(schema_abbreviations, table_name, row)) }.uniq
end

def extract_association_for_record(record, schema_abbreviations, primary_key_table, rows, reflection)
association = rows.collect do |row|
if row[primary_key_table[table_name]].to_s == record.id.to_s && !row[primary_key_table[reflection.klass.table_name]].nil?
reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.klass.table_name, row))
end
end

return association.uniq.compact
end

def extract_record(schema_abbreviations, table_name, row) def extract_record(schema_abbreviations, table_name, row)
row.inject({}) do |record, pair| record = {}
prefix, column_name = schema_abbreviations[pair.first] row.each do |column, value|
record[column_name] = pair.last if prefix == table_name prefix, column_name = schema_abbreviations[column]
record record[column_name] = value if prefix == table_name
end end
end return record

end

def reflect_on_included_associations(associations)
[ associations ].flatten.collect { |association| reflect_on_association(association) }
end

def select_all_rows(options, schema_abbreviations, reflections)
connection.select_all(
construct_finder_sql_with_included_associations(options, schema_abbreviations, reflections),
"#{name} Load Including Associations"
)
end
end end
end end
end end
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def loaded?
@loaded @loaded
end end


def target
@target
end

def target=(t) def target=(t)
@target = t @target = t
@loaded = true @loaded = true
Expand Down
6 changes: 5 additions & 1 deletion activerecord/lib/active_record/base.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -618,6 +618,10 @@ def columns
def columns_hash def columns_hash
@columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash } @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
end end

def column_names
@column_names ||= columns_hash.keys
end


# Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count", # Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count",
# and columns used for single table inheritance has been removed. # and columns used for single table inheritance has been removed.
Expand All @@ -640,7 +644,7 @@ def column_methods_hash


# Resets all the cached information about columns, which will cause they to be reloaded on the next request. # Resets all the cached information about columns, which will cause they to be reloaded on the next request.
def reset_column_information def reset_column_information
@columns = @columns_hash = @content_columns = @dynamic_methods_hash = nil @column_names = @columns = @columns_hash = @content_columns = @dynamic_methods_hash = nil
end end


def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc: def reset_column_information_and_inheritable_attributes_for_all_subclasses#:nodoc:
Expand Down
6 changes: 5 additions & 1 deletion activerecord/lib/active_record/reflection.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -114,7 +114,11 @@ def name_to_class_name(name)
# Holds all the meta-data about an association as it was specified in the Active Record class. # Holds all the meta-data about an association as it was specified in the Active Record class.
class AssociationReflection < MacroReflection #:nodoc: class AssociationReflection < MacroReflection #:nodoc:
def klass def klass
active_record.send(:compute_type, (name_to_class_name(name.id2name))) @klass ||= active_record.send(:compute_type, (name_to_class_name(name.id2name)))
end

def table_name
@table_name ||= klass.table_name
end end


private private
Expand Down

0 comments on commit 49d0f0c

Please sign in to comment.