diff --git a/db/migrate/migration_utils/migration_squasher.rb b/db/migrate/migration_utils/migration_squasher.rb new file mode 100644 index 0000000000..7884902908 --- /dev/null +++ b/db/migrate/migration_utils/migration_squasher.rb @@ -0,0 +1,82 @@ +# This migration aggregates the migrations passed in migrations into one given as a block +# heredoc +module Migration + class MigrationSquasher + class IncompleteMigrationsError < ::StandardError + end + + #define all the following methods as class methods + class << self + + def squash(aggregated_versions) + intersection = aggregated_versions & all_versions + + if intersection == [] + + # No migrations that this migration aggregates have already been + # applied. In this case, run the aggregated migration passed as a block + yield + + elsif intersection == aggregated_versions + + # All migrations that this migration aggregates have already + # been applied. In this case, remove the information about those + # migrations from the schema_migrations table and we're done. + ActiveRecord::Base.connection.execute <<-SQL + (intersection.map { |version| <<-CONDITIONS }).join(" OR ") + DELETE FROM + #{quoted_schema_migrations_table_name} + WHERE + SQL + #{version_column_for_comparison} = #{quote_value(version)} + CONDITIONS + + else + + missing = aggregated_versions - intersection + + # Only a part of the migrations that this migration aggregates + # have already been applied. In this case, fail miserably. + raise IncompleteMigrationsError, <<-MESSAGE.split("\n").map(&:strip!).join(" ") + "\n" + It appears you are migrating from an incompatible version. + Your database has only some migrations to be squashed. + Please update your installation to a version including all the + aggregated migrations and run this migration again. + The following migrations are missing: #{missing} + MESSAGE + + end + + end + + + private + + def all_versions + table = Arel::Table.new(schema_migrations_table_name) + ActiveRecord::Base.connection.select_values(table.project(table['version'])) + end + + def schema_migrations_table_name + ActiveRecord::Migrator.schema_migrations_table_name + end + + def quoted_schema_migrations_table_name + ActiveRecord::Base.connection.quote_table_name(schema_migrations_table_name) + end + + def quoted_version_column_name + ActiveRecord::Base.connection.quote_table_name("version") + end + + def version_column_for_comparison + "#{quoted_schema_migrations_table_name}.#{quoted_version_column_name}" + end + + def quote_value s + ActiveRecord::Base.connection.quote(s) + end + + end + end +end +