class NoBrainer::QueryRunner::TableOnDemand

Public Instance Methods

call(env) click to toggle source
# File lib/no_brainer/query_runner/table_on_demand.rb, line 2
def call(env)
  @runner.call(env)
# Not matching in RqlRuntimeError because we can get a DocumentNotPersisted
rescue RuntimeError => e
  if table_info = handle_table_on_demand_exception?(env, e)
    auto_create_table(env, *table_info)
    retry
  end
  raise
end
handle_table_on_demand_exception?(env, e) click to toggle source
# File lib/no_brainer/query_runner/table_on_demand.rb, line 13
def handle_table_on_demand_exception?(env, e)
  /^Table `(.+)\.(.+)` does not exist\.$/.match(e.message).try(:[], 1..2)
end

Private Instance Methods

auto_create_table(env, db_name, table_name) click to toggle source
# File lib/no_brainer/query_runner/table_on_demand.rb, line 19
def auto_create_table(env, db_name, table_name)
  model = NoBrainer::Document.all(:types => [:user, :nobrainer])
                             .detect { |m| m.table_name == table_name }
  if model.nil?
    raise "Auto table creation is not working for `#{db_name}.#{table_name}` -- Can't find the corresponding model."
  end

  if env[:last_auto_create_table] == [db_name, table_name]
    raise "Auto table creation is not working for `#{db_name}.#{table_name}`"
  end
  env[:last_auto_create_table] = [db_name, table_name]

  create_options = model.table_create_options
  begin
    NoBrainer.run(:db => db_name) do |r|
      r.table_create(table_name, create_options.reject { |k,_| k.in? [:name, :write_acks] })
    end
  rescue RuntimeError => e
    # We might have raced with another table create
    raise unless e.message =~ /Table `#{db_name}\.#{table_name}` already exists/
  end

  # Prevent duplicate table errors on a cluster.
  # Workaround from https://github.com/rethinkdb/rethinkdb/issues/4898#issuecomment-270267740
  NoBrainer.run(:db => 'rethinkdb') do |r|
    r.table('table_config')
     .filter({db: db_name, name: table_name})
     .order_by('id')
     .slice(1)
     .delete
  end

  if create_options[:write_acks] && create_options[:write_acks] != 'single'
    NoBrainer.run(:db => db_name) do |r|
      r.table(table_name).config().update(:write_acks => create_options[:write_acks])
    end
  end
end