<commit_before>module Bullet
  module SaveWithBulletSupport
    def save(*args)
      was_new_record = new_record?
      super(*args).tap do |result|
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
      end
    end

    def save!(*args)
      was_new_record = new_record?
      super(*args).tap do |result|
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
      end
    end
  end

  module ActiveRecord
    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
        end
      end

      ::ActiveRecord::Base.prepend(SaveWithBulletSupport)

      ::ActiveRecord::Relation.class_eval do
        alias_method :origin_records, :records
        # 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 = origin_records
          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.class_eval do
        alias_method :origin_preloaders_for_one, :preloaders_for_one

        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
          origin_preloaders_for_one(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
          records = origin_load_target

          if Bullet.start?
            if records.size > 1
              if self.is_a? ::ActiveRecord::Associations::ThroughAssociation
                Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
                association = self.owner.association self.through_reflection.name
                association.target.each do |through_record|
                  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
                end
              end
              Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
            end
            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? && !reflection.has_cached_counter?
            Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
          end
          origin_empty?
        end
<commit_msg>association.target can be singular for through_association #302<commit_after>module Bullet
  module SaveWithBulletSupport
    def save(*args)
      was_new_record = new_record?
      super(*args).tap do |result|
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
      end
    end

    def save!(*args)
      was_new_record = new_record?
      super(*args).tap do |result|
        Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
      end
    end
  end

  module ActiveRecord
    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
        end
      end

      ::ActiveRecord::Base.prepend(SaveWithBulletSupport)

      ::ActiveRecord::Relation.class_eval do
        alias_method :origin_records, :records
        # 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 = origin_records
          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.class_eval do
        alias_method :origin_preloaders_for_one, :preloaders_for_one

        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
          origin_preloaders_for_one(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
          records = origin_load_target

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

{'fraction_non_alphanumeric': 0.07548596929127903, 'fraction_numerical': 0.0012858331442402238, 'mean_word_length': 2.263079960513327, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1049312', 'n_tokens_mistral': 3635, 'n_tokens_neox': 3517, 'n_words': 662}