module Bullet::ActiveRecord

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Relation.class_eval do
    alias_method :origin_to_a, :to_a
    # if select a collection of objects, then these objects have possible to cause N+1 query.
    # if select only one object, then the only one object has impossible to cause N+1 query.
    def to_a
      records = origin_to_a
      if records.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
        Bullet::Detector::CounterCache.add_possible_objects(records)
      elsif records.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
        Bullet::Detector::CounterCache.add_impossible_object(records.first)
      end
      records
    end
  end
  ::ActiveRecord::AssociationPreload::ClassMethods.class_eval do
    alias_method :origin_preload_associations, :preload_associations
    # include query for one to many associations.
    # keep this eager loadings.
    def preload_associations(records, associations, preload_options={})
      records = [records].flatten.compact.uniq
      return if records.empty?
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
      origin_preload_associations(records, associations, preload_options={})
    end
  end
  ::ActiveRecord::FinderMethods.class_eval do
    # add includes in scope
    alias_method :origin_find_with_associations, :find_with_associations
    def find_with_associations
      records = origin_find_with_associations
      associations = (@eager_load_values + @includes_values).uniq
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
      records
    end
  end
  ::ActiveRecord::Associations::ClassMethods::JoinDependency.class_eval do
    alias_method :origin_instantiate, :instantiate
    alias_method :origin_construct_association, :construct_association
    def instantiate(rows)
      @bullet_eager_loadings = {}
      records = origin_instantiate(rows)
      @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
        objects = eager_loadings_hash.keys
        Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
      end
      records
    end
    # call join associations
    def construct_association(record, join, row)
      result = origin_construct_association(record, join, row)
      associations = join.reflection.name
      Bullet::Detector::Association.add_object_associations(record, associations)
      Bullet::Detector::NPlusOneQuery.call_association(record, associations)
      @bullet_eager_loadings[record.class] ||= {}
      @bullet_eager_loadings[record.class][record] ||= Set.new
      @bullet_eager_loadings[record.class][record] << associations
      result
    end
  end
::ActiveRecord::Associations::AssociationCollection.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_load_target
    end
    alias_method :origin_first, :first
    def first(*args)
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_first(*args)
    end
    alias_method :origin_last, :last
    def last(*args)
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_last(*args)
    end
    alias_method :origin_empty?, :empty?
    def empty?
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_empty?
    end
  end
  ::ActiveRecord::Associations::AssociationProxy.class_eval do
    # call has_one and belong_to association
    alias_method :origin_load_target, :load_target
    def load_target
      # avoid stack level too deep
      result = origin_load_target
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? { |c| c.include?("load_target") }
      Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
      result
    end
    alias_method :origin_set_inverse_instance, :set_inverse_instance
    def set_inverse_instance(record, instance)
      if record && we_can_set_the_inverse_on_this?(record)
        Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
      end
      origin_set_inverse_instance(record, instance)
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    def has_cached_counter?
      result = origin_has_cached_counter?
      Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
      result
    end
  end
  ::ActiveRecord::Associations::HasManyThroughAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    def has_cached_counter?
      result = origin_has_cached_counter?
      Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
      result
    end
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Relation.class_eval do
    alias_method :origin_to_a, :to_a
    # if select a collection of objects, then these objects have possible to cause N+1 query.
    # if select only one object, then the only one object has impossible to cause N+1 query.
    def to_a
      records = origin_to_a
      if records.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
        Bullet::Detector::CounterCache.add_possible_objects(records)
      elsif records.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
        Bullet::Detector::CounterCache.add_impossible_object(records.first)
      end
      records
    end
  end
  ::ActiveRecord::Associations::Preloader.class_eval do
    # include query for one to many associations.
    # keep this eager loadings.
    alias_method :origin_initialize, :initialize
    def initialize(records, associations, preload_scope = nil)
      origin_initialize(records, associations, preload_scope)
      records = [records].flatten.compact.uniq
      return if records.empty?
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
    end
  end
  ::ActiveRecord::FinderMethods.class_eval do
    # add includes in scope
    alias_method :origin_find_with_associations, :find_with_associations
    def find_with_associations
      records = origin_find_with_associations
      associations = (eager_load_values + includes_values).uniq
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
      records
    end
  end
  ::ActiveRecord::Associations::JoinDependency.class_eval do
    alias_method :origin_instantiate, :instantiate
    alias_method :origin_construct_association, :construct_association
    def instantiate(rows)
      @bullet_eager_loadings = {}
      records = origin_instantiate(rows)
      @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
        objects = eager_loadings_hash.keys
        Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
      end
      records
    end
    # call join associations
    def construct_association(record, join, row)
      result = origin_construct_association(record, join, row)
      associations = join.reflection.name
      Bullet::Detector::Association.add_object_associations(record, associations)
      Bullet::Detector::NPlusOneQuery.call_association(record, associations)
      @bullet_eager_loadings[record.class] ||= {}
      @bullet_eager_loadings[record.class][record] ||= Set.new
      @bullet_eager_loadings[record.class][record] << associations
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_load_target
    end
    alias_method :origin_empty?, :empty?
    def empty?
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_empty?
    end
  end
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
    # call has_one and belongs_to associations
    alias_method :origin_reader, :reader
    def reader(force_reload = false)
      result = origin_reader(force_reload)
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
      result
    end
  end
  ::ActiveRecord::Associations::Association.class_eval do
    alias_method :origin_set_inverse_instance, :set_inverse_instance
    def set_inverse_instance(record)
      if record && invertible_for?(record)
        Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
      end
      origin_set_inverse_instance(record)
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    def has_cached_counter?(reflection = reflection())
      result = origin_has_cached_counter?(reflection)
      Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
      result
    end
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Relation.class_eval do
    alias_method :origin_to_a, :to_a
    # if select a collection of objects, then these objects have possible to cause N+1 query.
    # if select only one object, then the only one object has impossible to cause N+1 query.
    def to_a
      records = origin_to_a
      if records.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
        Bullet::Detector::CounterCache.add_possible_objects(records)
      elsif records.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
        Bullet::Detector::CounterCache.add_impossible_object(records.first)
      end
      records
    end
  end
  ::ActiveRecord::Associations::Preloader.class_eval do
    # include query for one to many associations.
    # keep this eager loadings.
    alias_method :origin_initialize, :initialize
    def initialize(records, associations, preload_scope = nil)
      origin_initialize(records, associations, preload_scope)
      records = [records].flatten.compact.uniq
      return if records.empty?
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
    end
  end
  ::ActiveRecord::FinderMethods.class_eval do
    # add includes in scope
    alias_method :origin_find_with_associations, :find_with_associations
    def find_with_associations
      records = origin_find_with_associations
      associations = (eager_load_values + includes_values).uniq
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
      records
    end
  end
  ::ActiveRecord::Associations::JoinDependency.class_eval do
    alias_method :origin_instantiate, :instantiate
    alias_method :origin_construct_association, :construct_association
    def instantiate(rows)
      @bullet_eager_loadings = {}
      records = origin_instantiate(rows)
      @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
        objects = eager_loadings_hash.keys
        Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
      end
      records
    end
    # call join associations
    def construct_association(record, join, row)
      result = origin_construct_association(record, join, row)
      associations = join.reflection.name
      Bullet::Detector::Association.add_object_associations(record, associations)
      Bullet::Detector::NPlusOneQuery.call_association(record, associations)
      @bullet_eager_loadings[record.class] ||= {}
      @bullet_eager_loadings[record.class][record] ||= Set.new
      @bullet_eager_loadings[record.class][record] << associations
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_load_target
    end
    alias_method :origin_empty?, :empty?
    def empty?
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_empty?
    end
  end
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
    # call has_one and belongs_to associations
    alias_method :origin_reader, :reader
    def reader(force_reload = false)
      result = origin_reader(force_reload)
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
      result
    end
  end
  ::ActiveRecord::Associations::Association.class_eval do
    alias_method :origin_set_inverse_instance, :set_inverse_instance
    def set_inverse_instance(record)
      if record && invertible_for?(record)
        Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
      end
      origin_set_inverse_instance(record)
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    def has_cached_counter?(reflection = reflection())
      result = origin_has_cached_counter?(reflection)
      Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
      result
    end
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Relation.class_eval do
    alias_method :origin_to_a, :to_a
    # if select a collection of objects, then these objects have possible to cause N+1 query.
    # if select only one object, then the only one object has impossible to cause N+1 query.
    def to_a
      records = origin_to_a
      if records.first.class.name !~ /^HABTM_/
        if records.size > 1
          Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
          Bullet::Detector::CounterCache.add_possible_objects(records)
        elsif records.size == 1
          Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
          Bullet::Detector::CounterCache.add_impossible_object(records.first)
        end
      end
      records
    end
  end
  ::ActiveRecord::Associations::Preloader.class_eval do
    alias_method :origin_preloaders_on, :preloaders_on
    def preloaders_on(association, records, scope)
      if records.first.class.name !~ /^HABTM_/
        records.each do |record|
          Bullet::Detector::Association.add_object_associations(record, association)
        end
        Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
      end
      origin_preloaders_on(association, records, scope)
    end
  end
  ::ActiveRecord::FinderMethods.class_eval do
    # add includes in scope
    alias_method :origin_find_with_associations, :find_with_associations
    def find_with_associations
      records = origin_find_with_associations
      associations = (eager_load_values + includes_values).uniq
      records.each do |record|
        Bullet::Detector::Association.add_object_associations(record, associations)
      end
      Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
      records
    end
  end
  ::ActiveRecord::Associations::JoinDependency.class_eval do
    alias_method :origin_instantiate, :instantiate
    alias_method :origin_construct_model, :construct_model
    def instantiate(result_set, aliases)
      @bullet_eager_loadings = {}
      records = origin_instantiate(result_set, aliases)
      @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
        objects = eager_loadings_hash.keys
        Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
      end
      records
    end
    # call join associations
    def construct_model(record, node, row, model_cache, id, aliases)
      result = origin_construct_model(record, node, row, model_cache, id, aliases)
      associations = node.reflection.name
      Bullet::Detector::Association.add_object_associations(record, associations)
      Bullet::Detector::NPlusOneQuery.call_association(record, associations)
      @bullet_eager_loadings[record.class] ||= {}
      @bullet_eager_loadings[record.class][record] ||= Set.new
      @bullet_eager_loadings[record.class][record] << associations
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
      origin_load_target
    end
    alias_method :origin_empty?, :empty?
    def empty?
      Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      origin_empty?
    end
  end
  ::ActiveRecord::Associations::SingularAssociation.class_eval do
    # call has_one and belongs_to associations
    alias_method :origin_reader, :reader
    def reader(force_reload = false)
      result = origin_reader(force_reload)
      if @owner.class.name !~ /^HABTM_/
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
      end
      result
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    def has_cached_counter?(reflection = reflection())
      result = origin_has_cached_counter?(reflection)
      Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
      result
    end
  end
end

def construct_association(record, join, row)

call join associations
def construct_association(record, join, row)
  result = origin_construct_association(record, join, row)
  associations = join.reflection.name
  Bullet::Detector::Association.add_object_associations(record, associations)
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
  @bullet_eager_loadings[record.class] ||= {}
  @bullet_eager_loadings[record.class][record] ||= Set.new
  @bullet_eager_loadings[record.class][record] << associations
  result
end

def construct_association(record, join, row)

call join associations
def construct_association(record, join, row)
  result = origin_construct_association(record, join, row)
  associations = join.reflection.name
  Bullet::Detector::Association.add_object_associations(record, associations)
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
  @bullet_eager_loadings[record.class] ||= {}
  @bullet_eager_loadings[record.class][record] ||= Set.new
  @bullet_eager_loadings[record.class][record] << associations
  result
end

def construct_association(record, join, row)

call join associations
def construct_association(record, join, row)
  result = origin_construct_association(record, join, row)
  associations = join.reflection.name
  Bullet::Detector::Association.add_object_associations(record, associations)
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
  @bullet_eager_loadings[record.class] ||= {}
  @bullet_eager_loadings[record.class][record] ||= Set.new
  @bullet_eager_loadings[record.class][record] << associations
  result
end

def construct_model(record, node, row, model_cache, id, aliases)

call join associations
def construct_model(record, node, row, model_cache, id, aliases)
  result = origin_construct_model(record, node, row, model_cache, id, aliases)
  associations = node.reflection.name
  Bullet::Detector::Association.add_object_associations(record, associations)
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
  @bullet_eager_loadings[record.class] ||= {}
  @bullet_eager_loadings[record.class][record] ||= Set.new
  @bullet_eager_loadings[record.class][record] << associations
  result
end

def empty?

def empty?
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_empty?
end

def empty?

def empty?
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_empty?
end

def empty?

def empty?
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_empty?
end

def empty?

def empty?
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_empty?
end

def find_with_associations

def find_with_associations
  records = origin_find_with_associations
  associations = (@eager_load_values + @includes_values).uniq
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
  records
end

def find_with_associations

def find_with_associations
  records = origin_find_with_associations
  associations = (eager_load_values + includes_values).uniq
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
  records
end

def find_with_associations

def find_with_associations
  records = origin_find_with_associations
  associations = (eager_load_values + includes_values).uniq
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
  records
end

def find_with_associations

def find_with_associations
  records = origin_find_with_associations
  associations = (eager_load_values + includes_values).uniq
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
  records
end

def first(*args)

def first(*args)
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_first(*args)
end

def has_cached_counter?

def has_cached_counter?
  result = origin_has_cached_counter?
  Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
  result
end

def has_cached_counter?

def has_cached_counter?
  result = origin_has_cached_counter?
  Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
  result
end

def has_cached_counter?(reflection = reflection())

def has_cached_counter?(reflection = reflection())
  result = origin_has_cached_counter?(reflection)
  Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
  result
end

def has_cached_counter?(reflection = reflection())

def has_cached_counter?(reflection = reflection())
  result = origin_has_cached_counter?(reflection)
  Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
  result
end

def has_cached_counter?(reflection = reflection())

def has_cached_counter?(reflection = reflection())
  result = origin_has_cached_counter?(reflection)
  Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
  result
end

def initialize(records, associations, preload_scope = nil)

def initialize(records, associations, preload_scope = nil)
  origin_initialize(records, associations, preload_scope)
  records = [records].flatten.compact.uniq
  return if records.empty?
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
end

def initialize(records, associations, preload_scope = nil)

def initialize(records, associations, preload_scope = nil)
  origin_initialize(records, associations, preload_scope)
  records = [records].flatten.compact.uniq
  return if records.empty?
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
end

def instantiate(rows)

def instantiate(rows)
  @bullet_eager_loadings = {}
  records = origin_instantiate(rows)
  @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
    objects = eager_loadings_hash.keys
    Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
  end
  records
end

def instantiate(rows)

def instantiate(rows)
  @bullet_eager_loadings = {}
  records = origin_instantiate(rows)
  @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
    objects = eager_loadings_hash.keys
    Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
  end
  records
end

def instantiate(rows)

def instantiate(rows)
  @bullet_eager_loadings = {}
  records = origin_instantiate(rows)
  @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
    objects = eager_loadings_hash.keys
    Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
  end
  records
end

def instantiate(result_set, aliases)

def instantiate(result_set, aliases)
  @bullet_eager_loadings = {}
  records = origin_instantiate(result_set, aliases)
  @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
    objects = eager_loadings_hash.keys
    Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
  end
  records
end

def last(*args)

def last(*args)
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_last(*args)
end

def load_target

def load_target
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_load_target
end

def load_target

def load_target
  # avoid stack level too deep
  result = origin_load_target
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? { |c| c.include?("load_target") }
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
  result
end

def load_target

def load_target
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_load_target
end

def load_target

def load_target
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  origin_load_target
end

def load_target

def load_target
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
  origin_load_target
end

def preload_associations(records, associations, preload_options={})

keep this eager loadings.
include query for one to many associations.
def preload_associations(records, associations, preload_options={})
  records = [records].flatten.compact.uniq
  return if records.empty?
  records.each do |record|
    Bullet::Detector::Association.add_object_associations(record, associations)
  end
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
  origin_preload_associations(records, associations, preload_options={})
end

def preloaders_on(association, records, scope)

def preloaders_on(association, records, scope)
  if records.first.class.name !~ /^HABTM_/
    records.each do |record|
      Bullet::Detector::Association.add_object_associations(record, association)
    end
    Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
  end
  origin_preloaders_on(association, records, scope)
end

def reader(force_reload = false)

def reader(force_reload = false)
  result = origin_reader(force_reload)
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
  result
end

def reader(force_reload = false)

def reader(force_reload = false)
  result = origin_reader(force_reload)
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
  result
end

def reader(force_reload = false)

def reader(force_reload = false)
  result = origin_reader(force_reload)
  if @owner.class.name !~ /^HABTM_/
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
    Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
  end
  result
end

def set_inverse_instance(record, instance)

def set_inverse_instance(record, instance)
  if record && we_can_set_the_inverse_on_this?(record)
    Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
  end
  origin_set_inverse_instance(record, instance)
end

def set_inverse_instance(record)

def set_inverse_instance(record)
  if record && invertible_for?(record)
    Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
  end
  origin_set_inverse_instance(record)
end

def set_inverse_instance(record)

def set_inverse_instance(record)
  if record && invertible_for?(record)
    Bullet::Detector::NPlusOneQuery.add_impossible_object(record)
  end
  origin_set_inverse_instance(record)
end

def to_a

if select only one object, then the only one object has impossible to cause N+1 query.
if select a collection of objects, then these objects have possible to cause N+1 query.
def to_a
  records = origin_to_a
  if records.size > 1
    Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
    Bullet::Detector::CounterCache.add_possible_objects(records)
  elsif records.size == 1
    Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
    Bullet::Detector::CounterCache.add_impossible_object(records.first)
  end
  records
end

def to_a

if select only one object, then the only one object has impossible to cause N+1 query.
if select a collection of objects, then these objects have possible to cause N+1 query.
def to_a
  records = origin_to_a
  if records.size > 1
    Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
    Bullet::Detector::CounterCache.add_possible_objects(records)
  elsif records.size == 1
    Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
    Bullet::Detector::CounterCache.add_impossible_object(records.first)
  end
  records
end

def to_a

if select only one object, then the only one object has impossible to cause N+1 query.
if select a collection of objects, then these objects have possible to cause N+1 query.
def to_a
  records = origin_to_a
  if records.size > 1
    Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
    Bullet::Detector::CounterCache.add_possible_objects(records)
  elsif records.size == 1
    Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
    Bullet::Detector::CounterCache.add_impossible_object(records.first)
  end
  records
end

def to_a

if select only one object, then the only one object has impossible to cause N+1 query.
if select a collection of objects, then these objects have possible to cause N+1 query.
def to_a
  records = origin_to_a
  if records.first.class.name !~ /^HABTM_/
    if records.size > 1
      Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
      Bullet::Detector::CounterCache.add_possible_objects(records)
    elsif records.size == 1
      Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
      Bullet::Detector::CounterCache.add_impossible_object(records.first)
    end
  end
  records
end