20190726175042_add_case_insensitive_index_to_tags.rb 1.8 KB

123456789101112131415161718192021222324252627282930313233343536
  1. # frozen_string_literal: true
  2. class AddCaseInsensitiveIndexToTags < ActiveRecord::Migration[5.2]
  3. disable_ddl_transaction!
  4. def up
  5. Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_ary.each do |row|
  6. canonical_tag_id = row['ids'].split(',').first
  7. redundant_tag_ids = row['ids'].split(',')[1..]
  8. safety_assured do
  9. execute "UPDATE accounts_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')}) AND NOT EXISTS (SELECT t1.tag_id FROM accounts_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.account_id = t0.account_id)"
  10. execute "UPDATE statuses_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')}) AND NOT EXISTS (SELECT t1.tag_id FROM statuses_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.status_id = t0.status_id)"
  11. execute "UPDATE featured_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')}) AND NOT EXISTS (SELECT t1.tag_id FROM featured_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.account_id = t0.account_id)"
  12. end
  13. Tag.where(id: redundant_tag_ids).in_batches.delete_all
  14. end
  15. begin
  16. safety_assured { execute 'CREATE UNIQUE INDEX CONCURRENTLY index_tags_on_name_lower ON tags (lower(name))' }
  17. rescue ActiveRecord::StatementInvalid
  18. remove_index :tags, name: 'index_tags_on_name_lower'
  19. raise
  20. end
  21. remove_index :tags, name: 'index_tags_on_name'
  22. remove_index :tags, name: 'hashtag_search_index'
  23. end
  24. def down
  25. add_index :tags, :name, unique: true, algorithm: :concurrently
  26. safety_assured { execute 'CREATE INDEX CONCURRENTLY hashtag_search_index ON tags (name text_pattern_ops)' }
  27. remove_index :tags, name: 'index_tags_on_name_lower'
  28. end
  29. end