summaryrefslogtreecommitdiff
path: root/db/migrate/20161207231620_fixup_environment_name_uniqueness.rb
blob: f73e4f6c99b19762a024fa410f77fabe0432d5e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class FixupEnvironmentNameUniqueness < ActiveRecord::Migration
  include Gitlab::Database::MigrationHelpers

  DOWNTIME = true
  DOWNTIME_REASON = 'Renaming non-unique environments'

  def up
    environments = Arel::Table.new(:environments)

    # Get all [project_id, name] pairs that occur more than once
    finder_sql = environments
      .group(environments[:project_id], environments[:name])
      .having(Arel.sql("COUNT(1)").gt(1))
      .project(environments[:project_id], environments[:name])
      .to_sql

    conflicting = connection.exec_query(finder_sql)

    conflicting.rows.each do |project_id, name|
      fix_duplicates(project_id, name)
    end
  end

  def down
    # Nothing to do
  end

  # Rename conflicting environments by appending "-#{id}" to all but the first
  def fix_duplicates(project_id, name)
    environments = Arel::Table.new(:environments)
    finder_sql = environments
      .where(environments[:project_id].eq(project_id))
      .where(environments[:name].eq(name))
      .order(environments[:id].asc)
      .project(environments[:id], environments[:name])
      .to_sql

    # Now we have the data for all the conflicting rows
    conflicts = connection.exec_query(finder_sql).rows
    conflicts.shift # Leave the first row alone

    conflicts.each do |id, name|
      update_sql =
        Arel::UpdateManager.new(ActiveRecord::Base)
          .table(environments)
          .set(environments[:name] => name + "-" + id.to_s)
          .where(environments[:id].eq(id))
          .to_sql

      connection.exec_update(update_sql, self.class.name, [])
    end
  end
end