Skip to content

Commit

Permalink
fix migration error
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamfall committed Nov 6, 2023
1 parent cc9ccec commit c11fecc
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class AddConstraintsToMostRecentForFormAnswerTransitions < ActiveRecord::Migrati
disable_ddl_transaction!

def up
Rake::Task['statesman:backfill_most_recent'].invoke("FormAnswer")
Rake::Task['statesman:backfill_most_recent_fixed'].invoke("FormAnswer")
FormAnswerTransition.where(most_recent: nil).update_all(most_recent: false)
add_index :form_answer_transitions, [:form_answer_id, :most_recent], unique: true, where: "most_recent", name: "index_form_answer_transitions_parent_most_recent", algorithm: :concurrently rescue ""
change_column_null :form_answer_transitions, :most_recent, false
Expand Down
62 changes: 62 additions & 0 deletions lib/tasks/statesman.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
namespace :statesman do
desc "Set most_recent to false for old transitions and to true for the " \
"latest one. Safe to re-run"
task :backfill_most_recent_fixed, [:parent_model_name] => :environment do |_, args|
parent_model_name = args.parent_model_name
abort("Parent model name must be specified") unless parent_model_name

parent_class = parent_model_name.constantize
transition_class = parent_class.transition_class
parent_fk = "#{parent_model_name.demodulize.underscore}_id"
updated_at = if ActiveRecord.default_timezone == :utc
Time.now.utc
else
Time.now
end

total_models = parent_class.count
done_models = 0
batch_size = 500

parent_class.find_in_batches(batch_size: batch_size) do |models|
ActiveRecord::Base.transaction(requires_new: true) do
if Statesman::Adapters::ActiveRecord.database_supports_partial_indexes?
# Set all transitions' most_recent to FALSE
transition_class.where(parent_fk => models.map(&:id)).
update_all(most_recent: false, updated_at: updated_at)
else
transition_class.where(parent_fk => models.map(&:id)).
update_all(most_recent: nil, updated_at: updated_at)
end

# Set current transition's most_recent to TRUE
initial_t = transition_class.arel_table
subsequent_t = initial_t.alias

later_row_for_same_parent = initial_t[parent_fk].
eq(subsequent_t[parent_fk]).
and(initial_t[:sort_key].
lt(subsequent_t[:sort_key]))

no_later_row = subsequent_t[:id].eq(nil)
in_current_parent_batch = initial_t[parent_fk].in(models.map(&:id))

latest_ids_query = initial_t.join(subsequent_t, Arel::Nodes::OuterJoin).
on(later_row_for_same_parent).
where(no_later_row.and(in_current_parent_batch)).
project(initial_t[:id]).to_sql

latest_ids = transition_class.find_by_sql(latest_ids_query).
to_a.collect(&:id)

transition_class.where(id: latest_ids).
update_all(most_recent: true, updated_at: updated_at)
end

done_models += batch_size
puts "Updated #{transition_class.name.pluralize} for " \
"#{[done_models, total_models].min}/#{total_models} " \
"#{parent_model_name.pluralize}"
end
end
end

0 comments on commit c11fecc

Please sign in to comment.