gitlab-org--gitlab-foss/lib/gitlab/background_migration/fix_first_mentioned_in_comm...

100 lines
3.2 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Class that fixes the incorrectly set authored_date within
# issue_metrics table
class FixFirstMentionedInCommitAt
SUB_BATCH_SIZE = 500
# rubocop: disable Style/Documentation
class TmpIssueMetrics < ActiveRecord::Base
include EachBatch
self.table_name = 'issue_metrics'
def self.from_2020
where(first_mentioned_in_commit_at_condition)
end
def self.first_mentioned_in_commit_at_condition
if columns_hash['first_mentioned_in_commit_at'].sql_type == 'timestamp without time zone'
'EXTRACT(YEAR FROM first_mentioned_in_commit_at) > 2019'
else
"EXTRACT(YEAR FROM first_mentioned_in_commit_at at time zone 'UTC') > 2019"
end
end
end
# rubocop: enable Style/Documentation
def perform(start_id, end_id)
scope(start_id, end_id).each_batch(of: SUB_BATCH_SIZE, column: :issue_id) do |sub_batch|
first, last = sub_batch.pick(Arel.sql('min(issue_id), max(issue_id)'))
# The query need to be reconstructed because .each_batch modifies the default scope
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/330510
inner_query = TmpIssueMetrics
.unscoped
.merge(scope(first, last))
.from("issue_metrics, #{lateral_query}")
.select('issue_metrics.issue_id', 'first_authored_date.authored_date')
.where('issue_metrics.first_mentioned_in_commit_at > first_authored_date.authored_date')
TmpIssueMetrics.connection.execute <<~UPDATE_METRICS
WITH cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
#{inner_query.to_sql}
)
UPDATE issue_metrics
SET
first_mentioned_in_commit_at = cte.authored_date
FROM
cte
WHERE
cte.issue_id = issue_metrics.issue_id
UPDATE_METRICS
end
mark_job_as_succeeded(start_id, end_id)
end
private
def mark_job_as_succeeded(*arguments)
Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
'FixFirstMentionedInCommitAt',
arguments
)
end
def scope(start_id, end_id)
TmpIssueMetrics.from_2020.where(issue_id: start_id..end_id)
end
def lateral_query
<<~SQL
LATERAL (
SELECT MIN(first_authored_date.authored_date) as authored_date
FROM merge_requests_closing_issues,
LATERAL (
SELECT id
FROM merge_request_diffs
WHERE merge_request_id = merge_requests_closing_issues.merge_request_id
ORDER BY id DESC
LIMIT 1
) last_diff_id,
LATERAL (
SELECT authored_date
FROM merge_request_diff_commits
WHERE
merge_request_diff_id = last_diff_id.id
ORDER BY relative_order DESC
LIMIT 1
) first_authored_date
WHERE merge_requests_closing_issues.issue_id = issue_metrics.issue_id
) first_authored_date
SQL
end
end
end
end