class ARDatabaseDuplicator::CapturedSchema

Attributes

db[R]
schema[R]
schema_file_name[R]

Public Class Methods

new(ardb, schema_file_name) click to toggle source
# File lib/ar_database_duplicator.rb, line 682
def initialize(ardb, schema_file_name)
  @db = ardb
  self.schema_file_name = schema_file_name
  parse_schema
end

Public Instance Methods

recorded_assume_migrated() click to toggle source
# File lib/ar_database_duplicator.rb, line 700
def recorded_assume_migrated
  @recorded_assume_migrated ||= []
end
recorded_initialize_schema() click to toggle source
# File lib/ar_database_duplicator.rb, line 704
def recorded_initialize_schema
  @recorded_initialize_schema ||= []
end
schema_for(table_name) click to toggle source
# File lib/ar_database_duplicator.rb, line 692
def schema_for(table_name)
  [create_table_command(table_name), index_commands(table_name)].join("\n")
end
table_commands_for(table_name) click to toggle source
# File lib/ar_database_duplicator.rb, line 688
def table_commands_for(table_name)
  recorded_table_commands[table_name]
end
table_names() click to toggle source
# File lib/ar_database_duplicator.rb, line 696
def table_names
  recorded_table_commands.keys
end

Private Instance Methods

create_table_command(table_name) click to toggle source
# File lib/ar_database_duplicator.rb, line 718
def create_table_command(table_name)
  create_command = recorded_table_commands[table_name].find { |x| x.first == :create_table }
  if create_command
    (["create_table #{create_command[0..-2].map(&:inspect).join(', ')} do |t|"] + recorded_table_columns[table_name] + ['end']).join("\n")
  else
    ''
  end
end
index_commands(table_name) click to toggle source
# File lib/ar_database_duplicator.rb, line 727
def index_commands(table_name)
  recorded_table_commands[table_name].find_all { |x| x.first == :add_index }.inject([]) do |commands, command|
    commands << "add_index " + command[1..-2].map(&:inspect).join(', ')
  end.join("\n")
end
parse_schema() click to toggle source
# File lib/ar_database_duplicator.rb, line 743
def parse_schema
  self.schema = File.read(schema_file_name)

  # Create the two interceptors.
  # The first for the create table blocks to get the columns, the second for the create_table and add_index commands.

  # This is the column interceptor.
  table_definition = recording_table_definition
  table_commands = recorded_table_commands
  table_columns = recorded_table_columns
  assume_migrated = recorded_assume_migrated
  initialize_schema = recorded_initialize_schema
  # This interceptor helps us learn what tables we will be defining by intercepting the important schema commands.
  # Additionally determine the final assume_migrated_upto_version arguments.
  # These will be used for each sub database created.
  # The 1.8.x style of define_singleton_method
  schema_klass_singleton = class << ActiveRecord::Schema; self; end
  schema_klass_singleton.send(:define_method, :method_missing) do |name, *arguments, &block|
    if name.to_sym == :create_table
      # Pull out the table name
      table_name = arguments.first
      # Record the creation command
      table_commands[table_name] << ([name] + arguments + [block] )

      # Now lets get what is inside that block so we know what columns there are.
      # Start with no columns
      table_definition.column_commands = []
      # Call the block with our recorder (instead of a normal table definition instance)
      block.call(table_definition)
      # Save off all of the column commands
      table_columns[table_name] = table_definition.column_commands
    elsif name.to_sym == :add_index
      table_commands[arguments.first] << ([name] + arguments + [block] )
    elsif name.to_sym == :assume_migrated_upto_version
      assume_migrated.replace ([name] + arguments + [block] )
    elsif name.to_sym == :initialize_schema_migrations_table
      initialize_schema.replace ([name] + arguments + [block] )
    end
  end


  # Now with the above interceptors/recorders in place, eval the schema capture all of the data.
  # This is a safety thing. Just in case examining the schema causes a change
  # (which it never should) we don't want to touch our source.
  db.with_connection("schema_eval", nil, true) do
    eval(schema)
  end

  # Now to remove the interceptor/recorders defined above
  schema_klass_singleton.send(:remove_method, :method_missing)

end
recorded_table_columns() click to toggle source
# File lib/ar_database_duplicator.rb, line 737
def recorded_table_columns
  @recorded_table_columns ||= Hash.new
end
recorded_table_commands() click to toggle source
# File lib/ar_database_duplicator.rb, line 733
def recorded_table_commands
  @recorded_table_commands ||= Hash.new { |hash, key| hash[key] = [] }
end
recording_table_definition() click to toggle source
# File lib/ar_database_duplicator.rb, line 796
  def recording_table_definition
    unless @recording_table_definition
      @recording_table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(nil)
      @recording_table_definition.instance_eval <<-EOV, __FILE__, __LINE__ + 1
        def column_commands
          @column_commands
        end

        def column_commands=(x)
          @column_commands = x
        end
      EOV

      %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
        @recording_table_definition.instance_eval <<-EOV, __FILE__, __LINE__ + 1
          def #{column_type}(*args)
            column_options = args.extract_options!
            column_names = args
            command_args = column_options.map { |x| x.map(&:inspect).join(' => ') }
            column_names.each do |name|
              column_commands << "  t.#{column_type} " + command_args.unshift(name.inspect).join(', ')
            end
          end
        EOV
      end
    end
    @recording_table_definition
  end
schema=(x) click to toggle source
# File lib/ar_database_duplicator.rb, line 710
def schema=(x)
  @schema = x
end
schema_file_name=(x) click to toggle source
# File lib/ar_database_duplicator.rb, line 714
def schema_file_name=(x)
  @schema_file_name = x
end