class Squcumber::Redshift::Mock::Database

Constants

DELETE_DB_WHEN_FINISHED
TEST_DB_NAME_OVERRIDE

Public Class Methods

new(production_database) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 10
def initialize(production_database)
  @production_database = production_database or raise ArgumentError, 'No production database provided'

  test_db_name_postfix = TEST_DB_NAME_OVERRIDE.empty? ? rand(10000..99999) : TEST_DB_NAME_OVERRIDE
  @test_db_name = "test_env_#{test_db_name_postfix}"

  if @production_database.exec("select datname from pg_database where datname like '%#{@test_db_name}%'").num_tuples != 0
    @production_database.exec("drop database #{@test_db_name}")
  end
  @production_database.exec("create database #{@test_db_name}")

  @testing_database = PG.connect(
    host: ENV['REDSHIFT_HOST'],
    port: ENV['REDSHIFT_PORT'],
    dbname: @test_db_name,
    user: ENV['REDSHIFT_USER'],
    password: ENV['REDSHIFT_PASSWORD']
  )
end

Public Instance Methods

copy_table_def_from_prod(schema, table) click to toggle source

Redshift does not allow to copy a table schema to another database, i.e. ‘create table some_db.some_table (like another_db.some_table)` cannot be used.

# File lib/squcumber-redshift/mock/database.rb, line 56
def copy_table_def_from_prod(schema, table)
  create_table_statement = _get_create_table_statement(schema, table)
  exec(create_table_statement)
end
copy_table_defs_from_prod(tables) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 61
def copy_table_defs_from_prod(tables)
  tables.each do |obj|
    obj.each { |schema, table| copy_table_def_from_prod(schema, table) }
  end
end
destroy() click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 87
def destroy
  @testing_database.close()

  if DELETE_DB_WHEN_FINISHED
    attempts = 0
    begin
      attempts += 1
      @production_database.exec("drop database #{@test_db_name}")
    rescue PG::ObjectInUse
      sleep 5
      retry unless attempts >= 3
    end
  else
    puts "\nTest database has been kept alive: #{@test_db_name}"
  end

  @production_database.close()
end
exec(statement) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 44
def exec(statement)
  @testing_database.exec(statement)
end
Also aliased as: query
exec_file(path) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 49
def exec_file(path)
  exec(File.read("#{path}"))
end
Also aliased as: query_file
insert_mock_values(schema_and_table, mock) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 74
def insert_mock_values(schema_and_table, mock)
  schema, table = schema_and_table.split('.')
  keys = []
  vals = []
  mock.each do |key, value|
    unless value.nil?
      keys << key
      vals << (value.is_a?(String) ? "'#{value}'" : value)
    end
  end
  exec("insert into #{schema}.#{table} (#{keys.join(',')}) values (#{vals.join(',')})") unless vals.empty?
end
mock(mock) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 67
def mock(mock)
  mock.each do |schema_and_table, data|
    raise "Mock data for #{schema_and_table} is not correctly formatted: must be Array but was #{data.class}" unless data.is_a?(Array)
    data.each { |datum| insert_mock_values(schema_and_table, datum) }
  end
end
query(statement)
Alias for: exec
query_file(path)
Alias for: exec_file
setup(schemas) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 30
def setup(schemas)
  schemas.each do |schema|
    exec("drop schema if exists #{schema} cascade")
    exec("create schema #{schema}")
  end
end
truncate_all_tables() click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 37
def truncate_all_tables
  @testing_database
    .exec("select schemaname || '.' || tablename as schema_and_table from pg_tables where tableowner = '#{ENV['REDSHIFT_USER']}'")
    .map { |row| row['schema_and_table'] }
    .each { |schema_and_table| exec("truncate table #{schema_and_table}") }
end

Private Instance Methods

_get_column_definitions(table_definition) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 131
def _get_column_definitions(table_definition)
  table_definition.map { |definition| "#{definition['column']} #{definition['type']} default null" }
end
_get_create_table_statement(schema, table) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 108
def _get_create_table_statement(schema, table)
  @production_database.exec("set search_path to '$user', #{schema};")
  table_schema = @production_database.query("select * from pg_table_def where schemaname = '#{schema}' and tablename = '#{table}';")
  raise "Sorry, there is no table information for #{schema}.#{table}" if table_schema.num_tuples == 0

  distkey = _get_table_distkey(table_schema)
  sortkeys = _get_table_sortkeys(table_schema).join(',')
  definitions = _get_column_definitions(table_schema).join(',')

  table_distkey  = "distkey(#{distkey})"            unless distkey.nil?
  table_sortkeys = "sortkey(#{sortkeys})" unless sortkeys.empty?

  "create table if not exists #{schema}.#{table} (#{definitions}) #{table_distkey} #{table_sortkeys};"
end
_get_table_distkey(table_definition) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 123
def _get_table_distkey(table_definition)
  table_definition.select { |definition| definition['distkey'].eql?('t') }[0]['column'] rescue nil
end
_get_table_sortkeys(table_definition) click to toggle source
# File lib/squcumber-redshift/mock/database.rb, line 127
def _get_table_sortkeys(table_definition)
  table_definition.sort_by { |e| e['sortkey'].to_i }.select { |e| e['sortkey'].to_i != 0 }.map { |e| e['column'] } rescue nil
end