Проблема проектирования Ruby для SQL Bulk Inserter - PullRequest
1 голос
/ 14 марта 2010

Это проблема дизайна Ruby. Как создать анализатор плоских файлов многократного использования, который может выполнять различные операции очистки данных для одного вызова, возвращать вызываемые результаты каждой операции очистки вызывающей стороне и выполнять массовые вставки SQL?

Теперь, до того, как кто-нибудь станет наркоман / обеспокоен, я написал этот код уже в очень скудном виде. Вот почему я прошу у любых наших рок-звезд Ruby какую-то помощь.

По сути, каждый раз, когда я хочу выполнить эту логику, я создаю два вложенных цикла с настраиваемой промежуточной обработкой, буферизую каждую обработанную строку в массив и выводим в БД в виде массовой вставки, когда достигается предел размера буфера.

Хотя я написал много помощников, основной шаблон - копирование, вставляемое каждый раз. Не очень СУХОЙ!

Вот пример кода Ruby / Pseudo того, что я повторяю.

lines_from_file.each do |line|

   line.match(/some regex/).each do |sub_str|
     # Process substring into useful format
       # EG1: Simple gsub() call
       # EG2: Custom function call to do complex scrubbing
       #      and matching, emitting results to array
       # EG3: Loop to match opening/closing/nested brackets 
       #      or other delimiters and emit results to array 
   end

   # Add processed lines to a buffer as SQL insert statement
   @buffer << PREPARED INSERT STATEMENT

   # Flush buffer when "buffer size limit reached" or "end of file"
   if sql_buffer_full || last_line_reached
     @dbc.insert(SQL INSERTS FROM BUFFER)
     @buffer = nil
   end

end

Я знаком с функциями Proc / Lambda. Однако, поскольку я хочу передать две отдельные процедуры одной функции, я не уверен, что делать дальше. У меня есть представление о том, как решить эту проблему, но мне бы очень хотелось посмотреть, что предлагают настоящие рубиисты?

За вами. Заранее спасибо: D

Ответы [ 2 ]

2 голосов
/ 14 марта 2010

В метод можно передать любое количество объектов proc, но они становятся обычными параметрами и теряют специальный синтаксис блока. Э.Г.

def import(lines_from_file,insert_statment_maker,special_logic) 
  lines_from_file.each do |line|    
  inserts = []    

  line.match(/some regex/).each do |sub_str|
    inserts << insert_statment_maker.call(sub_str)    
  end

  inserts = special_logic.call(inserts) if special_logics

  # Add processed lines to a buffer as SQL insert statement    
  @buffer << inserts

  # Flush buffer when "buffer size limit reached" or "end of file"    
  if sql_buffer_full || last_line_reached
    @dbc.insert(SQL INSERTS FROM BUFFER)
    @buffer = nil    
  end

end

Позвонить тебе бы ...

build_m_and_m_insert = Proc.new {|sub_str| ..... }
take_out_the_brown_ones = Proc.new {|inserts| .... }

import lines, build_m_and_m_insert, take_out_the_brown_ones
1 голос
/ 14 марта 2010

Хотя решение jeem, вероятно, идеально вам подходит, вы можете даже пойти немного дальше и создать два класса вместо Procs, читателя и писателя:

class InsertReader
  def initialize(lines)
    @lines = lines
  end

  def each
    @lines.each do |line|
      yield(make_insert(line))
    end
  end

  def make_insert line
    # return INSERT created for input line
  end
end

class InsertWriter
  def initialize
    @buff = []
    @buffsize = 100
  end

  def write insert
    @buff << insert
    flush if @buff.length > @buffsize
  end

  def flush
    @buff.each do |insert|
      DbAdapter.insert(insert)
    end
    @buff = []
  end
end

и вы используете их как

reader = InsertReader.new(my_file)
writer = InsertWriter.new
reader.each do |insert|
  writer.write insert
end
writer.flush

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

...