Add Rake task to migrate milestone data to new tables
This commit is contained in:
92
lib/tasks/migrate_milestones_and_statuses.rake
Normal file
92
lib/tasks/migrate_milestones_and_statuses.rake
Normal file
@@ -0,0 +1,92 @@
|
||||
namespace :milestones do
|
||||
|
||||
def generate_table_migration_sql(new_table:, old_table:, columns:)
|
||||
from_cols = ['id', *columns.keys]
|
||||
to_cols = ['id', *columns.values]
|
||||
<<~SQL
|
||||
INSERT INTO #{new_table} (#{to_cols.join(', ')})
|
||||
SELECT #{from_cols.join(', ')} FROM #{old_table};
|
||||
SQL
|
||||
end
|
||||
|
||||
def migrate_table!(new_table:, old_table:, columns:)
|
||||
puts "Migrating data from '#{old_table}' to '#{new_table}'..."
|
||||
result = ActiveRecord::Base.connection.execute(
|
||||
generate_table_migration_sql(old_table: old_table,
|
||||
new_table: new_table,
|
||||
columns: columns)
|
||||
|
||||
)
|
||||
puts "#{result.cmd_tuples} rows affected"
|
||||
end
|
||||
|
||||
def populate_column!(table:, column:, value:)
|
||||
puts "Populating column '#{column}' from table '#{table}' with '#{value}'..."
|
||||
result = ActiveRecord::Base.connection.execute(
|
||||
"UPDATE #{table} SET #{column} = '#{value}';"
|
||||
)
|
||||
puts "#{result.cmd_tuples} rows affected"
|
||||
end
|
||||
|
||||
def count_rows(table)
|
||||
ActiveRecord::Base.connection.query("SELECT COUNT(*) FROM #{table};")[0][0].to_i
|
||||
end
|
||||
|
||||
desc "Migrate milestones and milestone status data after making the model polymorphic"
|
||||
task migrate: :environment do
|
||||
# This script copies all milestone-related data from the old tables to
|
||||
# the new ones (preserving all primary keys). All 3 of the new tables
|
||||
# must be empty.
|
||||
#
|
||||
# To clear the new tables to test this script:
|
||||
#
|
||||
# DELETE FROM milestone_statuses;
|
||||
# DELETE FROM milestones;
|
||||
# DELETE FROM milestone_translations;
|
||||
#
|
||||
|
||||
start = Time.now
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
migrate_table! old_table: 'budget_investment_statuses',
|
||||
new_table: 'milestone_statuses',
|
||||
columns: {'name' => 'name',
|
||||
'description' => 'description',
|
||||
'hidden_at' => 'hidden_at',
|
||||
'created_at' => 'created_at',
|
||||
'updated_at' => 'updated_at'}
|
||||
|
||||
migrate_table! old_table: 'budget_investment_milestones',
|
||||
new_table: 'milestones',
|
||||
columns: {'investment_id' => 'milestoneable_id',
|
||||
'title' => 'title',
|
||||
'description' => 'description',
|
||||
'created_at' => 'created_at',
|
||||
'updated_at' => 'updated_at',
|
||||
'publication_date' => 'publication_date',
|
||||
'status_id' => 'status_id'}
|
||||
|
||||
populate_column! table: 'milestones',
|
||||
column: 'milestoneable_type',
|
||||
value: 'Budget::Investment'
|
||||
|
||||
migrate_table! old_table: 'budget_investment_milestone_translations',
|
||||
new_table: 'milestone_translations',
|
||||
columns: {'budget_investment_milestone_id' => 'milestone_id',
|
||||
'locale' => 'locale',
|
||||
'created_at' => 'created_at',
|
||||
'updated_at' => 'updated_at',
|
||||
'title' => 'title',
|
||||
'description' => 'description'}
|
||||
|
||||
puts "Verifying that all rows were copied..."
|
||||
unless count_rows('milestones') == count_rows('budget_investment_milestones') &&
|
||||
count_rows('milestone_statuses') == count_rows('budget_investment_statuses') &&
|
||||
count_rows('milestone_translations') == count_rows('budget_investment_milestone_translations')
|
||||
raise "Number of rows of old and new tables do not match! Rolling back transaction..."
|
||||
end
|
||||
end
|
||||
|
||||
puts "Finished in %.3f seconds" % (Time.now - start)
|
||||
end
|
||||
end
|
||||
121
spec/lib/tasks/milestones_spec.rb
Normal file
121
spec/lib/tasks/milestones_spec.rb
Normal file
@@ -0,0 +1,121 @@
|
||||
require "rails_helper"
|
||||
require "rake"
|
||||
|
||||
describe "Milestones tasks" do
|
||||
before do
|
||||
Rake.application.rake_require "tasks/migrate_milestones_and_statuses"
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
|
||||
describe "#migrate" do
|
||||
let :run_rake_task do
|
||||
Rake::Task["milestones:migrate"].reenable
|
||||
Rake.application.invoke_task "milestones:migrate"
|
||||
end
|
||||
|
||||
let!(:investment) { create(:budget_investment) }
|
||||
|
||||
before do
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"INSERT INTO budget_investment_statuses " +
|
||||
"(name, description, hidden_at, created_at, updated_at) " +
|
||||
"VALUES ('open', 'Good', NULL, '#{Time.current - 1.day}', '#{Time.current}');"
|
||||
)
|
||||
|
||||
status_id = ActiveRecord::Base.connection.execute(
|
||||
"SELECT MAX(id) FROM budget_investment_statuses;"
|
||||
).to_a.first["max"]
|
||||
|
||||
milestone_attributes = {
|
||||
investment_id: investment.id,
|
||||
title: "First",
|
||||
description: "Interesting",
|
||||
publication_date: Date.yesterday,
|
||||
status_id: status_id,
|
||||
created_at: Time.current - 1.day,
|
||||
updated_at: Time.current
|
||||
}
|
||||
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"INSERT INTO budget_investment_milestones " +
|
||||
"(#{milestone_attributes.keys.join(", ")}) " +
|
||||
"VALUES (#{milestone_attributes.values.map { |value| "'#{value}'"}.join(", ")})"
|
||||
)
|
||||
end
|
||||
|
||||
it "migrates statuses" do
|
||||
run_rake_task
|
||||
|
||||
expect(Milestone::Status.count).to be 1
|
||||
|
||||
status = Milestone::Status.first
|
||||
expect(status.name).to eq "open"
|
||||
expect(status.description).to eq "Good"
|
||||
expect(status.hidden_at).to be nil
|
||||
expect(status.created_at.to_date).to eq Date.yesterday
|
||||
expect(status.updated_at.to_date).to eq Date.today
|
||||
end
|
||||
|
||||
it "migrates milestones" do
|
||||
run_rake_task
|
||||
|
||||
expect(Milestone.count).to be 1
|
||||
|
||||
milestone = Milestone.first
|
||||
expect(milestone.milestoneable_id).to eq investment.id
|
||||
expect(milestone.milestoneable_type).to eq "Budget::Investment"
|
||||
expect(milestone.title).to eq "First"
|
||||
expect(milestone.description).to eq "Interesting"
|
||||
expect(milestone.publication_date).to eq Date.yesterday
|
||||
expect(milestone.status_id).to eq Milestone::Status.first.id
|
||||
expect(milestone.created_at.to_date).to eq Date.yesterday
|
||||
expect(milestone.updated_at.to_date).to eq Date.today
|
||||
end
|
||||
|
||||
context "Statuses had been deleted" do
|
||||
before do
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"INSERT INTO budget_investment_statuses " +
|
||||
"(name, description, hidden_at, created_at, updated_at) " +
|
||||
"VALUES ('deleted', 'Del', NULL, '#{Time.current - 1.day}', '#{Time.current}');"
|
||||
)
|
||||
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"DELETE FROM budget_investment_statuses WHERE name='deleted'"
|
||||
)
|
||||
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"INSERT INTO budget_investment_statuses " +
|
||||
"(name, description, hidden_at, created_at, updated_at) " +
|
||||
"VALUES ('new', 'New', NULL, '#{Time.current - 1.day}', '#{Time.current}');"
|
||||
)
|
||||
|
||||
status_id = ActiveRecord::Base.connection.execute(
|
||||
"SELECT MAX(id) FROM budget_investment_statuses;"
|
||||
).to_a.first["max"]
|
||||
|
||||
milestone_attributes = {
|
||||
investment_id: investment.id,
|
||||
title: "Last",
|
||||
description: "Different",
|
||||
publication_date: Date.yesterday,
|
||||
status_id: status_id,
|
||||
created_at: Time.current - 1.day,
|
||||
updated_at: Time.current
|
||||
}
|
||||
|
||||
ActiveRecord::Base.connection.execute(
|
||||
"INSERT INTO budget_investment_milestones " +
|
||||
"(#{milestone_attributes.keys.join(", ")}) " +
|
||||
"VALUES (#{milestone_attributes.values.map { |value| "'#{value}'"}.join(", ")})"
|
||||
)
|
||||
end
|
||||
|
||||
it "migrates the status id correctly" do
|
||||
run_rake_task
|
||||
|
||||
expect(Milestone.last.status_id).to eq Milestone::Status.last.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user