Лучшее место для проверки заголовков CSV-файла в kiba ETL - PullRequest
0 голосов
/ 12 февраля 2019

Мне нужно проверить, что:

  • строка заголовка присутствует * заголовок 1004 *
  • содержит специальный набор заголовков

Что лучше всего сделатьтот.У меня есть какое-то возможное решение, но я не знаю более идиоматического

  • Проверка перед запуском полного ETL для примера перед блоком Kiba.parse
  • Проверка в блоке pre_processвнутри ETL
  • проверьте источник ETL.Я предпочитаю этот, так как он будет более пригодным для повторного использования (необходимо передать обязательное поле в качестве параметров)

Обратите внимание, что даже если я могу проверить в блоке transform, какие поля доступны наrow, это решение кажется не очень эффективным, поскольку оно будет работать для каждой строки.

Любые подсказки приветствуются

1 Ответ

0 голосов
/ 17 февраля 2019

Существуют различные и все идиоматические способы достижения этого:

На уровне источника (передавая массив заголовков)

Вы можете использовать CSV без headers: true, чтопредлагает возможность точной проверки заголовков:

class CSVSource
  def initialize(filename:, csv_options:, expected_headers:)
  # SNIP

  def each
    CSV.foreach(filename, csv_options).with_index do |row, file_row_index|
      if file_row_index == 0
        check_headers!(actual: row.to_a, expected: expected_headers)
        next # do not propagate the headers row
      else
        yield(Hash[expected_headers.zip(row.to_a)])
      end
    end
  end

  def check_headers!(actual:, expected:)
  # SNIP - verify uniqueness, presence, raise a clear message if needed
end     

На уровне источника (позволяя вызывающей стороне определять поведение с помощью лямбды)

class CSVSource
  def initialize(after_headers_read_callback:, ...)
    @after_headers_read_callback = ...

  def each
    CSV.foreach(filename, csv_options).with_index do |row, file_row_index|
      if file_row_index == 0
        @after_headers_read_callback.call(row.to_a)
        next
      end
      # ...
    end
  end

Лямбда позволит вызывающей стороне определить ихсобственные проверки, повышение при необходимости и т. д., что лучше для повторного использования.

На уровне преобразования

Если вы хотите дополнительно отделить компоненты (например, отделить обработку заголовков от факта, что строки приходятиз источника CSV), вы можете использовать преобразование.

Я обычно использую этот дизайн, который позволяет лучше использовать повторно (здесь с источником CSV, который даст немного метаданных):

def transform_array_rows_to_hash_rows(after_headers_read_callback:)
  transform do |row|
    if row.fetch(:file_row_index) == 0
      @headers = row.fetch(:row)
      after_headers_read_callback.call(@headers)
      nil
    else
      Hash[@headers.zip(row.fetch(:row))].merge(
        filename: row.fetch(:filename),
        file_row_index: row.fetch(:file_row_index)
      )
    end
  end
end

Что не рекомендуется

Во всех случаях избегайте какой-либо обработки в самом Kiba.parse.Это лучший дизайн, гарантирующий, что ввод-вывод будет происходить только при вызове Kiba.run (так как он будет более ориентирован на будущее и будет поддерживать функции самоанализа в более поздних версиях Kiba).

Также с использованием pre_processне рекомендуется (хотя это будет работать), потому что это приведет к небольшому дублированию и т. д.

Надеюсь, это поможет, и дайте мне знать, если это не ясно!

...