<commit_before>module CSVImporter
  # Do the actual import.
  #
  # It iterates over the rows' models and persist them. It returns a `Report`.
  class Runner
    def self.call(*args)
      new(*args).call
    end

    include Virtus.model

    attribute :rows, Array[Row]
    attribute :when_invalid, Symbol

    attribute :report, Report, default: proc { Report.new }

    ImportAborted = Class.new(StandardError)

    # Persist the rows' model and return a `Report`
    def call
      if rows.empty?
        report.done!
        return report
      end

      report.in_progress!

      persist_rows!

      report.done!
      report
    rescue ImportAborted
      report.aborted!
      report
    end

    private

    def abort_when_invalid?
      when_invalid == :abort
    end

    def persist_rows!
      transaction do
        rows.each do |row|
          if row.model.persisted?
            if row.model.save
              report.updated_rows << row
            else
              report.failed_to_update_rows << row
              raise ImportAborted if abort_when_invalid?
            end
          else
            if row.model.save
              report.created_rows << row
            else
              report.failed_to_create_rows << row
              raise ImportAborted if abort_when_invalid?
            end
          end
        end
      end
    end

    def transaction(&block)
      rows.first.model.class.transaction(&block)
    end
  end
end<commit_msg>Improve Runner (?)<commit_after>module CSVImporter
  # Do the actual import.
  #
  # It iterates over the rows' models and persist them. It returns a `Report`.
  class Runner
    def self.call(*args)
      new(*args).call
    end

    include Virtus.model

    attribute :rows, Array[Row]
    attribute :when_invalid, Symbol

    attribute :report, Report, default: proc { Report.new }

    ImportAborted = Class.new(StandardError)

    # Persist the rows' model and return a `Report`
    def call
      if rows.empty?
        report.done!
        return report
      end

      report.in_progress!

      persist_rows!

      report.done!
      report
    rescue ImportAborted
      report.aborted!
      report
    end

    private

    def abort_when_invalid?
      when_invalid == :abort
    end

    def persist_rows!
      transaction do
        rows.each do |row|
          tags = []

          if row.model.persisted?
            tags << :update
          else
            tags << :create
          end

          if row.model.save
            tags << :success
          else
            tags << :failure
          end

          add_to_report(row, tags)
        end
      end
    end

    def add_to_report(row, tags)
      bucket = case tags
      when [ :create, :success ]
        report.created_rows
      when [ :create, :failure ]
        report.failed_to_create_rows
      when [ :update, :success ]
        report.updated_rows
      when [ :update, :failure ]
        report.failed_to_update_rows
      else
        raise "Invalid tags #{tags.inspect}"
      end

      bucket << row

      raise ImportAborted if abort_when_invalid? && tags[1] == :failure
    end

    def transaction(&block)
      rows.first.model.class.transaction(&block)
    end
  end
end
{'fraction_non_alphanumeric': 0.07162619120811559, 'fraction_numerical': 0.0003074085459575776, 'mean_word_length': 1.7483108108108107, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 3, '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': '1522238', 'n_tokens_mistral': 944, 'n_tokens_neox': 908, 'n_words': 261}