lib/departure/cli_generator.rb in departure-1.0.1 vs lib/departure/cli_generator.rb in departure-2.0.0

- old
+ new

@@ -1,51 +1,38 @@ +require 'departure/dsn' +require 'departure/option' require 'departure/alter_argument' +require 'departure/connection_details' +require 'departure/user_options' module Departure - # Represents the 'DSN' argument of Percona's pt-online-schema-change - # See https://www.percona.com/doc/percona-toolkit/2.0/pt-online-schema-change.html#dsn-options - class DSN - - # Constructor - # - # @param database [String, Symbol] - # @param table_name [String, Symbol] - def initialize(database, table_name) - @database = database - @table_name = table_name - end - - # Returns the pt-online-schema-change DSN string. See - # https://www.percona.com/doc/percona-toolkit/2.0/pt-online-schema-change.html#dsn-options - def to_s - "D=#{database},t=#{table_name}" - end - - private - - attr_reader :table_name, :database - end - # Generates the equivalent Percona's pt-online-schema-change command to the # given SQL statement - class CliGenerator # Command - BASE_COMMAND = 'pt-online-schema-change' - BASE_OPTIONS = %w( - --execute - --statistics - --recursion-method=none - --alter-foreign-keys-method=auto - ) + # + # --no-check-alter is used to allow running CHANGE COLUMN statements. For + # more details, check: www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html#cmdoption-pt-online-schema-change--[no]check-alter + # + class CliGenerator + COMMAND_NAME = 'pt-online-schema-change'.freeze + DEFAULT_OPTIONS = Set.new( + [ + Option.new('execute'), + Option.new('statistics'), + Option.new('alter-foreign-keys-method', 'auto'), + Option.new('no-check-alter') + ] + ).freeze - # Constructor + # TODO: Better doc. # + # Constructor. Specify any arguments to pass to pt-online-schema-change + # passing the PERCONA_ARGS env var when executing the migration + # # @param connection_data [Hash] - def initialize(connection_data) - @connection_data = connection_data - init_base_command - add_connection_details + def initialize(connection_details) + @connection_details = connection_details end # Generates the percona command. Fills all the connection credentials from # the current AR connection, but that can be amended via ENV-vars: # PERCONA_DB_HOST, PERCONA_DB_USER, PERCONA_DB_PASSWORD, PERCONA_DB_NAME @@ -55,13 +42,13 @@ # @param table_name [String] # @param statement [String] MySQL statement # @return [String] def generate(table_name, statement) alter_argument = AlterArgument.new(statement) - dsn = DSN.new(database, table_name) + dsn = DSN.new(connection_details.database, table_name) - "#{self} #{dsn} #{alter_argument}" + "#{command} #{all_options} #{dsn} #{alter_argument}" end # Generates the percona command for a raw MySQL statement. Fills all the # connection credentials from the current AR connection, but that can # amended via ENV-vars: PERCONA_DB_HOST, PERCONA_DB_USER, @@ -70,65 +57,29 @@ # # @param statement [String] MySQL statement # @return [String] def parse_statement(statement) alter_argument = AlterArgument.new(statement) - dsn = DSN.new(database, alter_argument.table_name) + dsn = DSN.new(connection_details.database, alter_argument.table_name) - "#{self} #{dsn} #{alter_argument}" + "#{command} #{all_options} #{dsn} #{alter_argument}" end private - attr_reader :connection_data + attr_reader :connection_details - # Sets up the command with its options - def init_base_command - @command = [BASE_COMMAND, BASE_OPTIONS.join(' ')] + def command + "#{COMMAND_NAME} #{connection_details}" end - # Adds the host, user and password, if present, to the command - def add_connection_details - @command.push("-h #{host}") - @command.push("-u #{user}") - @command.push("-p #{password}") if password.present? - end - - # Returns the command as a string that can be executed in a shell + # Returns all the arguments to execute pt-online-schema-change with # # @return [String] - def to_s - @command.join(' ') - end - - # Returns the database host name, defaulting to localhost. If PERCONA_DB_HOST - # is passed its value will be used instead - # - # @return [String] - def host - ENV['PERCONA_DB_HOST'] || connection_data[:host] || 'localhost' - end - - # Returns the database user. If PERCONA_DB_USER is passed its value will be - # used instead - # - # @return [String] - def user - ENV['PERCONA_DB_USER'] || connection_data[:username] - end - - # Returns the database user's password. If PERCONA_DB_PASSWORD is passed its - # value will be used instead - # - # @return [String] - def password - ENV['PERCONA_DB_PASSWORD'] || connection_data[:password] - end - - # TODO: Doesn't the abstract adapter already handle this somehow? - # Returns the database name. If PERCONA_DB_NAME is passed its value will be - # used instead - def database - ENV['PERCONA_DB_NAME'] || connection_data[:database] + def all_options + env_variable_options = UserOptions.new + global_configuration_options = UserOptions.new(Departure.configuration.global_percona_args) + options = env_variable_options.merge(global_configuration_options).merge(DEFAULT_OPTIONS) + options.to_a.join(' ') end end end