From 4c045876da051694aa4b9c69dd708283c5e2879d Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@gmail.com>
Date: Tue, 24 Sep 2013 17:21:19 -0700
Subject: push slice loading to it's own method so we can remove the type
 casting code

---
 .../associations/preloader/association.rb          | 21 ++++++++------------
 .../preloader/has_and_belongs_to_many.rb           | 23 +++++++++++-----------
 2 files changed, 20 insertions(+), 24 deletions(-)

(limited to 'activerecord/lib')

diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 63161d9744..cc8eefb234 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -3,9 +3,6 @@ module ActiveRecord
     class Preloader
       class Association #:nodoc:
         attr_reader :owners, :reflection, :preload_scope, :model, :klass
-        attr_reader :type_caster
-
-        IDENTITY_CASTER = lambda { |value| value } # :nodoc:
 
         def initialize(klass, owners, reflection, preload_scope)
           @klass         = klass
@@ -15,7 +12,6 @@ module ActiveRecord
           @model         = owners.first && owners.first.class
           @scope         = nil
           @owners_by_key = nil
-          @type_caster   = IDENTITY_CASTER
           @associated_records_by_owner = nil
         end
 
@@ -90,15 +86,9 @@ module ActiveRecord
             # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
             # Make several smaller queries if necessary or make one query if the adapter supports it
             sliced  = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
-            records = sliced.flat_map { |slice|
-              records = records_for(slice)
-              set_type_caster records, association_key_name
-              records
-            }
-            caster = type_caster
-            records.each do |record|
-              owner_key = caster.call record[association_key_name]
 
+            records = load_slices sliced
+            records.each do |record, owner_key|
               owners_map[owner_key].each do |owner|
                 records_by_owner[owner] << record
               end
@@ -111,7 +101,12 @@ module ActiveRecord
           @associated_records_by_owner = records_by_owner
         end
 
-        def set_type_caster(results, name)
+        def load_slices(slices)
+          slices.flat_map { |slice|
+            records_for(slice).to_a.map! { |record|
+              [record, record[association_key_name]]
+            }
+          }
         end
 
         def reflection_scope
diff --git a/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb
index 1c119d739f..996575f5aa 100644
--- a/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/preloader/has_and_belongs_to_many.rb
@@ -33,18 +33,19 @@ module ActiveRecord
         # Once we have used the join table column (in super), we manually instantiate the
         # actual records, ensuring that we don't create more than one instances of the same
         # record
-        def associated_records_by_owner(preloader)
-          return @associated_records_by_owner if @associated_records_by_owner
+        def load_slices(slices)
+          identity_map = {}
+          caster = nil
+          name = association_key_name
 
-          records = {}
-          @associated_records_by_owner = super.each_value do |rows|
-            rows.map! { |row| records[row[klass.primary_key]] ||= klass.instantiate(row) }
-          end
-        end
-
-        def set_type_caster(results, name)
-          caster = results.column_types.fetch(name, results.identity_type)
-          @type_caster = lambda { |value| caster.type_cast value }
+          slices.flat_map { |slice|
+            records = records_for(slice)
+            caster ||= records.column_types.fetch(name, records.identity_type)
+            records.map! { |row|
+              record = identity_map[row[klass.primary_key]] ||= klass.instantiate(row)
+              [record, caster.type_cast(row[name])]
+            }
+          }
         end
 
         def build_scope
-- 
cgit v1.2.3