module Ar::Preloader
Constants
- VERSION
Public Class Methods
check_association_exists(klass, association)
click to toggle source
# File lib/ar/preloader.rb, line 8 def self.check_association_exists(klass, association) case association when String, Symbol return klass.reflections.keys.include?(association.to_s) when Array association.each do |v| return false unless Ar::Preloader.check_association_exists(klass, v) end when Hash association.each_pair do |k,v| return false unless klass.reflections.keys.include?(k.to_s) associated_klass = klass.reflections[k.to_s].class_name.constantize case v when String, Symbol, Hash return false unless Ar::Preloader.check_association_exists(associated_klass, v) when Array v.each do |each_v| return false unless Ar::Preloader.check_association_exists(associated_klass, each_v) end else end end return true else return false end end
preload_association(list, association, inner_associations = [])
click to toggle source
# File lib/ar/preloader.rb, line 39 def self.preload_association(list, association, inner_associations = []) return if list.length == 0 case association when String, Symbol klass = list.first.class klass.send :attr_reader, "_#{association}".to_sym association_details = klass.reflections[association.to_s] association_klass = association_details.class_name.constantize case association_details when ActiveRecord::Reflection::HasManyReflection foreign_key = association_details.foreign_key association_pk = association_klass.primary_key list.each do |obj| instance_variable_name = "@_#{association}".to_sym obj.instance_variable_set(instance_variable_name, []) end query = <<-EOS SELECT distinct #{association_klass.table_name}.* FROM #{association_klass.table_name} WHERE #{association_klass.table_name}.#{foreign_key} in (#{ list.map{ |e| e[klass.primary_key.to_sym].try(:to_s) }.compact.join(",") }) EOS association_list = association_klass.find_by_sql(query).to_a if inner_associations.is_a?(Array) association_list.preload(*inner_associations) else association_list.preload(inner_associations) end list.each do |obj| instance_variable_name = "@_#{association}".to_sym association_list.select{ |e| e[foreign_key.to_sym] == obj[klass.primary_key.to_sym] }.each do |association_obj| each_list = obj.instance_variable_get(instance_variable_name) each_list << association_obj obj.instance_variable_set(instance_variable_name, each_list) end end when ActiveRecord::Reflection::BelongsToReflection foreign_key = association_details.foreign_key association_pk = association_klass.primary_key if list.map{ |e| e[foreign_key.to_sym] }.compact.length == 0 return true end query = <<-EOS SELECT distinct #{association_klass.table_name}.* FROM #{association_klass.table_name} WHERE #{association_klass.table_name}.#{association_klass.primary_key} in (#{ list.map{ |e| e[foreign_key.to_sym].try(:to_s) }.compact.join(",") }) EOS association_list = association_klass.find_by_sql(query).to_a if inner_associations.is_a?(Array) association_list.preload(*inner_associations) else association_list.preload(inner_associations) end association_map = association_list.map{ |e| [e[e.class.primary_key.to_sym], e] }.to_h list.each do |obj| if obj[foreign_key.to_sym].present? && association_map[obj[foreign_key.to_sym]].present? obj.instance_variable_set( "@_#{association}".to_sym, association_map[obj[foreign_key.to_sym]] ) end end when ActiveRecord::Reflection::HasAndBelongsToManyReflection foreign_key = association_details.foreign_key association_foreign_key = association_details.association_foreign_key join_table = association_details.join_table list.each do |obj| instance_variable_name = "@_#{association}".to_sym obj.instance_variable_set(instance_variable_name, []) end join_query = <<-EOS SELECT #{join_table}.#{foreign_key}, #{join_table}.#{association_foreign_key} FROM #{join_table} WHERE #{join_table}.#{foreign_key} IN (#{ list.map{ |e| e[klass.primary_key.to_sym].try(:to_s) }.compact.join(",") }) EOS join_entries = ActiveRecord::Base.connection.execute(join_query).to_a query = <<-EOS SELECT distinct #{association_klass.table_name}.* FROM #{association_klass.table_name} INNER JOIN #{join_table} ON #{join_table}.#{association_foreign_key} = #{association_klass.table_name}.#{association_klass.primary_key} WHERE #{join_table}.#{foreign_key} IN (#{ list.map{ |e| e[klass.primary_key.to_sym].try(:to_s) }.compact.join(",") }) EOS association_list = association_klass.find_by_sql(query).to_a if inner_associations.is_a?(Array) association_list.preload(*inner_associations) else association_list.preload(inner_associations) end list.each do |obj| instance_variable_name = "@_#{association}".to_sym association_key_list = join_entries.select{ |e| e[0] == obj[klass.primary_key.to_s] }.map(&:last) association_list.select{ |e| association_key_list.include?( e[association_klass.primary_key.to_s] ) }.each do |association_obj| each_list = obj.instance_variable_get(instance_variable_name) each_list << association_obj obj.instance_variable_set(instance_variable_name, each_list) end end else raise Ar::Preloader::Error.new("Unsupported association type: '#{association}'") end when Hash association.each_pair do |k,v| Ar::Preloader.preload_association(list, k, v) end end end