module Bullet::ActiveRecord

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Base.class_eval do
    class <<self
      alias_method :origin_find_by_sql, :find_by_sql
      def find_by_sql(sql, binds = [])
        result = origin_find_by_sql(sql, binds)
        if Bullet.start?
          if result.is_a? Array
            if result.size > 1
              Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
              Bullet::Detector::CounterCache.add_possible_objects(result)
            elsif result.size == 1
              Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
              Bullet::Detector::CounterCache.add_impossible_object(result.first)
            end
          elsif result.is_a? ::ActiveRecord::Base
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
            Bullet::Detector::CounterCache.add_impossible_object(result)
          end
        end
        result
      end
    end
  end
  ::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 Bullet.start?
        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::Persistence.class_eval do
    def _create_record_with_bullet(*args)
      _create_record_without_bullet(*args).tap do
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
      end
    end
    alias_method_chain :_create_record, :bullet
  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)
      if Bullet.start?
        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
  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
      if Bullet.start?
        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)
      end
      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)
      if Bullet.start?
        @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
      end
      records
    end
    # call join associations
    def construct_association(record, join, row)
      result = origin_construct_association(record, join, row)
      if Bullet.start?
        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
      end
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_load_target
    end
    alias_method :origin_include?, :include?
    def include?(object)
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_include?(object)
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_empty?, :empty?
    def empty?
      if Bullet.start? && !loaded? && !has_cached_counter?(@reflection)
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_empty?
    end
  end
  ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
    alias_method :origin_empty?, :empty?
    def empty?
      if Bullet.start? && !loaded?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      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 Bullet.start?
        unless @inversed
          Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
          Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        end
      end
      result
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_has_cached_counter?, :has_cached_counter?
    # rubocop:disable Style/MethodCallWithoutArgsParentheses
    def has_cached_counter?(reflection = reflection())
      result = origin_has_cached_counter?(reflection)
      if Bullet.start? && !result
        Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
      end
      result
    end
    # rubocop:enable Style/MethodCallWithoutArgsParentheses
  end
  ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
    def writer_with_bullet(record)
      Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
      writer_without_bullet(record)
    end
    alias_method_chain :writer, :bullet
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Base.class_eval do
    class <<self
      alias_method :origin_find_by_sql, :find_by_sql
      def find_by_sql(sql, binds = [])
        result = origin_find_by_sql(sql, binds)
        if Bullet.start?
          if result.is_a? Array
            if result.size > 1
              Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
              Bullet::Detector::CounterCache.add_possible_objects(result)
            elsif result.size == 1
              Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
              Bullet::Detector::CounterCache.add_impossible_object(result.first)
            end
          elsif result.is_a? ::ActiveRecord::Base
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
            Bullet::Detector::CounterCache.add_impossible_object(result)
          end
        end
        result
      end
    end
  end
  ::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 Bullet.start?
        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
      end
      records
    end
  end
  ::ActiveRecord::Persistence.class_eval do
    def _create_record_with_bullet(*args)
      _create_record_without_bullet(*args).tap do
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
      end
    end
    alias_method_chain :_create_record, :bullet
  end
  ::ActiveRecord::Associations::Preloader.class_eval do
    alias_method :origin_preloaders_on, :preloaders_on
    def preloaders_on(association, records, scope)
      if Bullet.start?
        records.compact!
        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
      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
      return origin_find_with_associations { |r| yield r } if block_given?
      records = origin_find_with_associations
      if Bullet.start?
        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)
      end
      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)
      if Bullet.start?
        @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
      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)
      if Bullet.start?
        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
      end
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
      end
      origin_load_target
    end
    alias_method :origin_empty?, :empty?
    def empty?
      if Bullet.start? && !has_cached_counter?(@reflection)
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_empty?
    end
    alias_method :origin_include?, :include?
    def include?(object)
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_include?(object)
    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 Bullet.start?
        if @owner.class.name !~ /^HABTM_/ && !@inversed
          Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
          Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        end
      end
      result
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_count_records, :count_records
    def count_records
      result = has_cached_counter?
      if Bullet.start? && !result
        Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
      end
      origin_count_records
    end
  end
  ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
    def writer_with_bullet(record)
      Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
      writer_without_bullet(record)
    end
    alias_method_chain :writer, :bullet
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Base.class_eval do
    class <<self
      alias_method :origin_find, :find
      def find(*args)
        result = origin_find(*args)
        if Bullet.start?
          if result.is_a? Array
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
            Bullet::Detector::CounterCache.add_possible_objects(result)
          elsif result.is_a? ::ActiveRecord::Base
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
            Bullet::Detector::CounterCache.add_impossible_object(result)
          end
        end
        result
      end
      alias_method :origin_find_by_sql, :find_by_sql
      def find_by_sql(sql, binds = [])
        result = origin_find_by_sql(sql, binds)
        if Bullet.start?
          if result.is_a? Array
            if result.size > 1
              Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
              Bullet::Detector::CounterCache.add_possible_objects(result)
            elsif result.size == 1
              Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
              Bullet::Detector::CounterCache.add_impossible_object(result.first)
            end
          elsif result.is_a? ::ActiveRecord::Base
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
            Bullet::Detector::CounterCache.add_impossible_object(result)
          end
        end
        result
      end
    end
  end
  ::ActiveRecord::Persistence.class_eval do
    def _create_record_with_bullet(*args)
      _create_record_without_bullet(*args).tap do
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
      end
    end
    alias_method_chain :_create_record, :bullet
  end
  ::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 Bullet.start?
        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
      end
      records
    end
  end
  ::ActiveRecord::Associations::Preloader.class_eval do
    alias_method :origin_preloaders_on, :preloaders_on
    def preloaders_on(association, records, scope)
      if Bullet.start?
        records.compact!
        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
      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
      return origin_find_with_associations { |r| yield r } if block_given?
      records = origin_find_with_associations
      if Bullet.start?
        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)
      end
      records
    end
  end
  ::ActiveRecord::Associations::JoinDependency.class_eval do
    alias_method :origin_instantiate, :instantiate
    alias_method :origin_construct, :construct
    alias_method :origin_construct_model, :construct_model
    def instantiate(result_set, aliases)
      @bullet_eager_loadings = {}
      records = origin_instantiate(result_set, aliases)
      if Bullet.start?
        @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
      end
      records
    end
    def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
      if Bullet.start?
        unless ar_parent.nil?
          parent.children.each do |node|
            key = aliases.column_alias(node, node.primary_key)
            id = row[key]
            next unless id.nil?
            associations = node.reflection.name
            Bullet::Detector::Association.add_object_associations(ar_parent, associations)
            Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
            @bullet_eager_loadings[ar_parent.class] ||= {}
            @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
            @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
          end
        end
      end
      origin_construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
    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)
      if Bullet.start?
        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
      end
      result
    end
  end
  ::ActiveRecord::Associations::CollectionAssociation.class_eval do
    # call one to many associations
    alias_method :origin_load_target, :load_target
    def load_target
      records = origin_load_target
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
        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
      end
      records
    end
    alias_method :origin_empty?, :empty?
    def empty?
      if Bullet.start? && !has_cached_counter?(@reflection)
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_empty?
    end
    alias_method :origin_include?, :include?
    def include?(object)
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      origin_include?(object)
    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 Bullet.start?
        if @owner.class.name !~ /^HABTM_/ && !@inversed
          Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
          if Bullet::Detector::NPlusOneQuery.impossible?(@owner)
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
          else
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
          end
        end
      end
      result
    end
  end
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
    alias_method :origin_many_empty?, :empty?
    def empty?
      result = origin_many_empty?
      if Bullet.start? && !has_cached_counter?(@reflection)
        Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
      end
      result
    end
    alias_method :origin_count_records, :count_records
    def count_records
      result = has_cached_counter?
      if Bullet.start? && !result
        Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
      end
      origin_count_records
    end
  end
  ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
    def writer_with_bullet(record)
      Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
      writer_without_bullet(record)
    end
    alias_method_chain :writer, :bullet
  end
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Base.extend(Module.new do
    def find_by_sql(sql, binds = [], preparable: nil, &block)
      result = super
      if Bullet.start?
        if result.is_a? Array
          if result.size > 1
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
            Bullet::Detector::CounterCache.add_possible_objects(result)
          elsif result.size == 1
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
            Bullet::Detector::CounterCache.add_impossible_object(result.first)
          end
        elsif result.is_a? ::ActiveRecord::Base
          Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
          Bullet::Detector::CounterCache.add_impossible_object(result)
        end
      end
      result
    end
  end)
  ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
  ::ActiveRecord::Relation.prepend(Module.new do
    # 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 records
      result = super
      if Bullet.start?
        if result.first.class.name !~ /^HABTM_/
          if result.size > 1
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
            Bullet::Detector::CounterCache.add_possible_objects(result)
          elsif result.size == 1
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
            Bullet::Detector::CounterCache.add_impossible_object(result.first)
          end
        end
      end
      result
    end
  end)
  ::ActiveRecord::Associations::Preloader.prepend(Module.new do
    def preloaders_for_one(association, records, scope)
      if Bullet.start?
        records.compact!
        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
      end
      super
    end
  end)
  ::ActiveRecord::FinderMethods.prepend(Module.new do
    # add includes in scope
    def find_with_associations
      return super { |r| yield r } if block_given?
      records = super
      if Bullet.start?
        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)
      end
      records
    end
  end)
  ::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
    if ::ActiveRecord::Associations::JoinDependency.instance_method(:instantiate).parameters.last[0] == :block
      # ActiveRecord >= 5.1.5
      def instantiate(result_set, &block)
        @bullet_eager_loadings = {}
        records = super
        if Bullet.start?
          @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
        end
        records
      end
    else
      # ActiveRecord <= 5.1.4
      def instantiate(result_set, aliases)
        @bullet_eager_loadings = {}
        records = super
        if Bullet.start?
          @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
        end
        records
      end
    end
    def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
      if Bullet.start?
        unless ar_parent.nil?
          parent.children.each do |node|
            key = aliases.column_alias(node, node.primary_key)
            id = row[key]
            next unless id.nil?
            associations = node.reflection.name
            Bullet::Detector::Association.add_object_associations(ar_parent, associations)
            Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
            @bullet_eager_loadings[ar_parent.class] ||= {}
            @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
            @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
          end
        end
      end
      super
    end
    # call join associations
    def construct_model(record, node, row, model_cache, id, aliases)
      result = super
      if Bullet.start?
        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
      end
      result
    end
  end)
  ::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
    def load_target
      records = super
      if Bullet.start?
        if is_a? ::ActiveRecord::Associations::ThroughAssociation
          refl = reflection.through_reflection
          Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
          association = owner.association refl.name
          Array(association.target).each do |through_record|
            Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
          end
          if refl.through_reflection?
            while refl.through_reflection?
              refl = refl.through_reflection
            end
            Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
          end
        end
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
        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
      end
      records
    end
    def empty?
      if Bullet.start? && !reflection.has_cached_counter?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      super
    end
    def include?(object)
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      super
    end
  end)
  ::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
    # call has_one and belongs_to associations
    def target
      result = super()
      if Bullet.start?
        if owner.class.name !~ /^HABTM_/ && !@inversed
          Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
          if Bullet::Detector::NPlusOneQuery.impossible?(owner)
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
          else
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
          end
        end
      end
      result
    end
  end)
  ::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
    def empty?
      result = super
      if Bullet.start? && !reflection.has_cached_counter?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      result
    end
    def count_records
      result = reflection.has_cached_counter?
      if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
        Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
      end
      super
    end
  end)
  ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
    def writer(record)
      Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
      super
    end
  end)
end

def self.enable

def self.enable
  require 'active_record'
  ::ActiveRecord::Base.extend(Module.new do
    def find_by_sql(sql, binds = [], preparable: nil, &block)
      result = super
      if Bullet.start?
        if result.is_a? Array
          if result.size > 1
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
            Bullet::Detector::CounterCache.add_possible_objects(result)
          elsif result.size == 1
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
            Bullet::Detector::CounterCache.add_impossible_object(result.first)
          end
        elsif result.is_a? ::ActiveRecord::Base
          Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
          Bullet::Detector::CounterCache.add_impossible_object(result)
        end
      end
      result
    end
  end)
  ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
  ::ActiveRecord::Relation.prepend(Module.new do
    # 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 records
      result = super
      if Bullet.start?
        if result.first.class.name !~ /^HABTM_/
          if result.size > 1
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
            Bullet::Detector::CounterCache.add_possible_objects(result)
          elsif result.size == 1
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
            Bullet::Detector::CounterCache.add_impossible_object(result.first)
          end
        end
      end
      result
    end
  end)
  ::ActiveRecord::Associations::Preloader.prepend(Module.new do
    def preloaders_for_one(association, records, scope)
      if Bullet.start?
        records.compact!
        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
      end
      super
    end
  end)
  ::ActiveRecord::FinderMethods.prepend(Module.new do
    # add includes in scope
    def find_with_associations
      return super { |r| yield r } if block_given?
      records = super
      if Bullet.start?
        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)
      end
      records
    end
  end)
  ::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
    def instantiate(result_set, &block)
      @bullet_eager_loadings = {}
      records = super
      if Bullet.start?
        @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
      end
      records
    end
    def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
      if Bullet.start?
        unless ar_parent.nil?
          parent.children.each do |node|
            key = aliases.column_alias(node, node.primary_key)
            id = row[key]
            next unless id.nil?
            associations = node.reflection.name
            Bullet::Detector::Association.add_object_associations(ar_parent, associations)
            Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
            @bullet_eager_loadings[ar_parent.class] ||= {}
            @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
            @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
          end
        end
      end
      super
    end
    # call join associations
    def construct_model(record, node, row, model_cache, id, aliases)
      result = super
      if Bullet.start?
        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
      end
      result
    end
  end)
  ::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
    def load_target
      records = super
      if Bullet.start?
        if is_a? ::ActiveRecord::Associations::ThroughAssociation
          Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
          association = owner.association reflection.through_reflection.name
          Array(association.target).each do |through_record|
            Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
          end
          if reflection.through_reflection != through_reflection
            Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
          end
        end
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
        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
      end
      records
    end
    def empty?
      if Bullet.start? && !reflection.has_cached_counter?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      super
    end
    def include?(object)
      if Bullet.start?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      super
    end
  end)
  ::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
    # call has_one and belongs_to associations
    def target
      result = super()
      if Bullet.start?
        if owner.class.name !~ /^HABTM_/ && !@inversed
          Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
          if Bullet::Detector::NPlusOneQuery.impossible?(owner)
            Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
          else
            Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
          end
        end
      end
      result
    end
  end)
  ::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
    def empty?
      result = super
      if Bullet.start? && !reflection.has_cached_counter?
        Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      end
      result
    end
    def count_records
      result = reflection.has_cached_counter?
      if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
        Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
      end
      super
    end
  end)
  ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
    def writer(record)
      Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
      super
    end
  end)
end

def _create_record_with_bullet(*args)

def _create_record_with_bullet(*args)
  _create_record_without_bullet(*args).tap do
    Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
  end
end

def _create_record_with_bullet(*args)

def _create_record_with_bullet(*args)
  _create_record_without_bullet(*args).tap do
    Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
  end
end

def _create_record_with_bullet(*args)

def _create_record_with_bullet(*args)
  _create_record_without_bullet(*args).tap do
    Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
  end
end

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
  if Bullet.start?
    unless ar_parent.nil?
      parent.children.each do |node|
        key = aliases.column_alias(node, node.primary_key)
        id = row[key]
        next unless id.nil?
        associations = node.reflection.name
        Bullet::Detector::Association.add_object_associations(ar_parent, associations)
        Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
        @bullet_eager_loadings[ar_parent.class] ||= {}
        @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
        @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
      end
    end
  end
  origin_construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
end

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
  if Bullet.start?
    unless ar_parent.nil?
      parent.children.each do |node|
        key = aliases.column_alias(node, node.primary_key)
        id = row[key]
        next unless id.nil?
        associations = node.reflection.name
        Bullet::Detector::Association.add_object_associations(ar_parent, associations)
        Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
        @bullet_eager_loadings[ar_parent.class] ||= {}
        @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
        @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
      end
    end
  end
  super
end

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)

def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
  if Bullet.start?
    unless ar_parent.nil?
      parent.children.each do |node|
        key = aliases.column_alias(node, node.primary_key)
        id = row[key]
        next unless id.nil?
        associations = node.reflection.name
        Bullet::Detector::Association.add_object_associations(ar_parent, associations)
        Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
        @bullet_eager_loadings[ar_parent.class] ||= {}
        @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
        @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
      end
    end
  end
  super
end

def construct_association(record, join, row)

call join associations
def construct_association(record, join, row)
  result = origin_construct_association(record, join, row)
  if Bullet.start?
    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
  end
  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)
  if Bullet.start?
    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
  end
  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)
  if Bullet.start?
    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
  end
  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 = super
  if Bullet.start?
    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
  end
  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 = super
  if Bullet.start?
    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
  end
  result
end

def count_records

def count_records
  result = has_cached_counter?
  if Bullet.start? && !result
    Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
  end
  origin_count_records
end

def count_records

def count_records
  result = has_cached_counter?
  if Bullet.start? && !result
    Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
  end
  origin_count_records
end

def count_records

def count_records
  result = reflection.has_cached_counter?
  if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
    Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
  end
  super
end

def count_records

def count_records
  result = reflection.has_cached_counter?
  if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
    Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
  end
  super
end

def empty?

def empty?
  if Bullet.start? && !loaded? && !has_cached_counter?(@reflection)
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_empty?
end

def empty?

def empty?
  if Bullet.start? && !loaded?
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_empty?
end

def empty?

def empty?
  if Bullet.start? && !has_cached_counter?(@reflection)
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_empty?
end

def empty?

def empty?
  if Bullet.start? && !has_cached_counter?(@reflection)
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_empty?
end

def empty?

def empty?
  result = origin_many_empty?
  if Bullet.start? && !has_cached_counter?(@reflection)
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  result
end

def empty?

def empty?
  if Bullet.start? && !reflection.has_cached_counter?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  super
end

def empty?

def empty?
  result = super
  if Bullet.start? && !reflection.has_cached_counter?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  result
end

def empty?

def empty?
  if Bullet.start? && !reflection.has_cached_counter?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  super
end

def empty?

def empty?
  result = super
  if Bullet.start? && !reflection.has_cached_counter?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  result
end

def find(*args)

def find(*args)
  result = origin_find(*args)
  if Bullet.start?
    if result.is_a? Array
      Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
      Bullet::Detector::CounterCache.add_possible_objects(result)
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_by_sql(sql, binds = [])

def find_by_sql(sql, binds = [])
  result = origin_find_by_sql(sql, binds)
  if Bullet.start?
    if result.is_a? Array
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_by_sql(sql, binds = [])

def find_by_sql(sql, binds = [])
  result = origin_find_by_sql(sql, binds)
  if Bullet.start?
    if result.is_a? Array
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_by_sql(sql, binds = [])

def find_by_sql(sql, binds = [])
  result = origin_find_by_sql(sql, binds)
  if Bullet.start?
    if result.is_a? Array
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_by_sql(sql, binds = [], preparable: nil, &block)

def find_by_sql(sql, binds = [], preparable: nil, &block)
  result = super
  if Bullet.start?
    if result.is_a? Array
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_by_sql(sql, binds = [], preparable: nil, &block)

def find_by_sql(sql, binds = [], preparable: nil, &block)
  result = super
  if Bullet.start?
    if result.is_a? Array
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    elsif result.is_a? ::ActiveRecord::Base
      Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
      Bullet::Detector::CounterCache.add_impossible_object(result)
    end
  end
  result
end

def find_with_associations

def find_with_associations
  records = origin_find_with_associations
  if Bullet.start?
    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)
  end
  records
end

def find_with_associations

def find_with_associations
  return origin_find_with_associations { |r| yield r } if block_given?
  records = origin_find_with_associations
  if Bullet.start?
    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)
  end
  records
end

def find_with_associations

def find_with_associations
  return origin_find_with_associations { |r| yield r } if block_given?
  records = origin_find_with_associations
  if Bullet.start?
    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)
  end
  records
end

def find_with_associations

add includes in scope
def find_with_associations
  return super { |r| yield r } if block_given?
  records = super
  if Bullet.start?
    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)
  end
  records
end

def find_with_associations

add includes in scope
def find_with_associations
  return super { |r| yield r } if block_given?
  records = super
  if Bullet.start?
    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)
  end
  records
end

def has_cached_counter?(reflection = reflection())

rubocop:disable Style/MethodCallWithoutArgsParentheses
def has_cached_counter?(reflection = reflection())
  result = origin_has_cached_counter?(reflection)
  if Bullet.start? && !result
    Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
  end
  result
end

def include?(object)

def include?(object)
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_include?(object)
end

def include?(object)

def include?(object)
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_include?(object)
end

def include?(object)

def include?(object)
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
  end
  origin_include?(object)
end

def include?(object)

def include?(object)
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  super
end

def include?(object)

def include?(object)
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
  end
  super
end

def initialize(records, associations, preload_scope = nil)

def initialize(records, associations, preload_scope = nil)
  origin_initialize(records, associations, preload_scope)
  if Bullet.start?
    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

def instantiate(rows)

def instantiate(rows)
  @bullet_eager_loadings = {}
  records = origin_instantiate(rows)
  if Bullet.start?
    @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
  end
  records
end

def instantiate(result_set, aliases)

def instantiate(result_set, aliases)
  @bullet_eager_loadings = {}
  records = origin_instantiate(result_set, aliases)
  if Bullet.start?
    @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
  end
  records
end

def instantiate(result_set, aliases)

def instantiate(result_set, aliases)
  @bullet_eager_loadings = {}
  records = origin_instantiate(result_set, aliases)
  if Bullet.start?
    @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
  end
  records
end

def instantiate(result_set, &block)

ActiveRecord >= 5.1.5
def instantiate(result_set, &block)
  @bullet_eager_loadings = {}
  records = super
  if Bullet.start?
    @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
  end
  records
end

def instantiate(result_set, aliases)

ActiveRecord <= 5.1.4
def instantiate(result_set, aliases)
  @bullet_eager_loadings = {}
  records = super
  if Bullet.start?
    @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
  end
  records
end

def instantiate(result_set, &block)

def instantiate(result_set, &block)
  @bullet_eager_loadings = {}
  records = super
  if Bullet.start?
    @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
  end
  records
end

def load_target

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

def load_target

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

def load_target

def load_target
  records = origin_load_target
  if Bullet.start?
    Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
    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
  end
  records
end

def load_target

def load_target
  records = super
  if Bullet.start?
    if is_a? ::ActiveRecord::Associations::ThroughAssociation
      refl = reflection.through_reflection
      Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
      association = owner.association refl.name
      Array(association.target).each do |through_record|
        Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
      end
      if refl.through_reflection?
        while refl.through_reflection?
          refl = refl.through_reflection
        end
        Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
      end
    end
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
    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
  end
  records
end

def load_target

def load_target
  records = super
  if Bullet.start?
    if is_a? ::ActiveRecord::Associations::ThroughAssociation
      Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
      association = owner.association reflection.through_reflection.name
      Array(association.target).each do |through_record|
        Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
      end
      if reflection.through_reflection != through_reflection
        Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
      end
    end
    Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
    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
  end
  records
end

def preloaders_for_one(association, records, scope)

def preloaders_for_one(association, records, scope)
  if Bullet.start?
    records.compact!
    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
  end
  super
end

def preloaders_for_one(association, records, scope)

def preloaders_for_one(association, records, scope)
  if Bullet.start?
    records.compact!
    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
  end
  super
end

def preloaders_on(association, records, scope)

def preloaders_on(association, records, scope)
  if Bullet.start?
    records.compact!
    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
  end
  origin_preloaders_on(association, records, scope)
end

def preloaders_on(association, records, scope)

def preloaders_on(association, records, scope)
  if Bullet.start?
    records.compact!
    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
  end
  origin_preloaders_on(association, records, scope)
end

def reader(force_reload = false)

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

def reader(force_reload = false)

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

def reader(force_reload = false)

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

def records

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 records
  result = super
  if Bullet.start?
    if result.first.class.name !~ /^HABTM_/
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    end
  end
  result
end

def records

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 records
  result = super
  if Bullet.start?
    if result.first.class.name !~ /^HABTM_/
      if result.size > 1
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
        Bullet::Detector::CounterCache.add_possible_objects(result)
      elsif result.size == 1
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
        Bullet::Detector::CounterCache.add_impossible_object(result.first)
      end
    end
  end
  result
end

def target

call has_one and belongs_to associations
def target
  result = super()
  if Bullet.start?
    if owner.class.name !~ /^HABTM_/ && !@inversed
      Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      if Bullet::Detector::NPlusOneQuery.impossible?(owner)
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
      else
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
      end
    end
  end
  result
end

def target

call has_one and belongs_to associations
def target
  result = super()
  if Bullet.start?
    if owner.class.name !~ /^HABTM_/ && !@inversed
      Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
      if Bullet::Detector::NPlusOneQuery.impossible?(owner)
        Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
      else
        Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
      end
    end
  end
  result
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 Bullet.start?
    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

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 Bullet.start?
    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
  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 Bullet.start?
    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
  end
  records
end

def writer(record)

def writer(record)
  Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
  super
end

def writer(record)

def writer(record)
  Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
  super
end

def writer_with_bullet(record)

def writer_with_bullet(record)
  Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
  writer_without_bullet(record)
end

def writer_with_bullet(record)

def writer_with_bullet(record)
  Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
  writer_without_bullet(record)
end

def writer_with_bullet(record)

def writer_with_bullet(record)
  Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
  writer_without_bullet(record)
end