Лучшее место для проверки заголовков CSV-файла в kiba ETL
Мне нужно проверить, что:
- строка заголовка присутствует
- заголовок содержит специфический набор заголовков
Какое лучшее место для этого. У меня есть какое-то возможное решение, но я не знаю более идиоматического
- Проверьте перед запуском полного ETL для примера перед
Kiba.parse
блок - Проверьте в
pre_process
блок внутри ETL - проверьте в источнике ETL. Я предпочитаю этот, так как он будет более многоразовым (необходимо передать обязательное поле в качестве параметров)
Обратите внимание, что даже если я могу проверить в transform
заблокировать какие поля доступны на row
Это решение кажется не очень эффективным, так как оно будет работать для каждой строки.
Любые советы приветствуются
1 ответ
Существуют различные и совершенно идиоматические способы достижения этой цели:
На уровне источника (передавая массив заголовков)
Ты можешь использовать 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
сам. Это лучший дизайн, чтобы гарантировать, что IO будет происходить только когда вы звоните Kiba.run
(поскольку он будет более ориентирован на будущее и будет поддерживать функции самоанализа в более поздних версиях Kiba).
Кроме того, используя pre_process
не рекомендуется (хотя это будет работать), потому что это приведет к небольшому дублированию и т. д.
Надеюсь, это поможет, и дайте мне знать, если это не ясно!