class PgClosureTreeRebuild::Builder

Constants

COLUMNS

Public Class Methods

new(table, hierarchies_table_name, options = {}) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 3
def initialize(table, hierarchies_table_name, options = {})
  @table = table
  @hierarchies_table_name = hierarchies_table_name.to_sym
  @id = options.delete(:id) || :id
  @parent_id = options.delete(:parent_id) || :parent_id
end

Public Instance Methods

chains() click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 26
def chains
  @chains ||= build_chains
end
rebuild(db) { || ... } click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 10
def rebuild(db)
  io = StringIO.new
  write_header(io)
  chains.each do |row|
    io.write([row.size].pack('n'))
    row.each { |v| write_integer(v, io) }
    yield if block_given?
  end
  write_close(io)
  copy(db, io)
end
tuples() click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 22
def tuples
  @tuples ||= @table.order(@parent_id).select_map([@id, @parent_id])
end

Private Instance Methods

build_chains() click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 32
def build_chains
  [].tap do |c|
    tuples.each { |tuple| c.concat(chains_for(tuple[0])) }
  end
end
chains_for(id) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 38
def chains_for(id)
  [].tap do |c|
    c << [id, id, 0]

    walk_up(id).each.with_index do |parent_id, index|
      c << [parent_id, id, index + 1]
    end
  end
end
copy(db, io) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 87
def copy(db, io)
  db[@hierarchies_table_name].truncate
  db.run('SET client_min_messages TO warning;')
  db.copy_into(
    @hierarchies_table_name,
    columns: COLUMNS, format: :binary, data: io.read
  )
end
index_tuples_by_id() click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 63
def index_tuples_by_id
  {}.tap do |c|
    tuples.each do |(id, parent_id)|
      c[id] = parent_id
    end
  end
end
tuples_hash() click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 59
def tuples_hash
  @tuples_hash ||= index_tuples_by_id
end
walk_up(id, cref = []) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 48
def walk_up(id, cref = [])
  parent_id = tuples_hash[id]
  return [] unless parent_id

  if cref.include?(parent_id)
    fail "Cycle reference detected: #{id} <=> #{parent_id}"
  end

  [parent_id] + walk_up(parent_id, cref + [parent_id])
end
write_close(io) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 82
def write_close(io)
  io.write([-1].pack('n'))
  io.rewind
end
write_header(io) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 77
def write_header(io)
  io.write("PGCOPY\n\377\r\n\0")
  io.write([0, 0].pack('NN'))
end
write_integer(value, io) click to toggle source
# File lib/pg_closure_tree_rebuild/builder.rb, line 71
def write_integer(value, io)
  buf = [value].pack('N')
  io.write([buf.bytesize].pack('N'))
  io.write(buf)
end