DEV: Migrate Chat::NotificationMention#notification_id to bigint (#28571)

`Notification#id` was migrated to `bigint` in 799a45a291
This commit is contained in:
Alan Guo Xiang Tan 2024-08-27 19:57:16 +08:00 committed by GitHub
parent 62c8904721
commit 82e75c8700
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 101 additions and 2 deletions

View File

@ -4,6 +4,10 @@ module Chat
class MentionNotification < ActiveRecord::Base
self.table_name = "chat_mention_notifications"
self.ignored_columns = [
:old_notification_id, # TODO remove once this column is removed. Migration to drop the column has not been written.
]
belongs_to :chat_mention, class_name: "Chat::Mention"
belongs_to :notification, dependent: :destroy
end
@ -13,8 +17,8 @@ end
#
# Table name: chat_mention_notifications
#
# chat_mention_id :integer not null
# notification_id :integer not null
# chat_mention_id :integer not null
# notification_id :bigint not null
#
# Indexes
#

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
class AddNewNotificationIdToChatMentionNotifications < ActiveRecord::Migration[7.1]
def up
# Create new column
execute "ALTER TABLE chat_mention_notifications ADD COLUMN new_notification_id BIGINT NOT NULL DEFAULT(0)"
# Mirror new `notification_id` values to `new_notification_id`
execute(<<~SQL)
CREATE FUNCTION mirror_chat_mention_notifications_notification_id()
RETURNS trigger AS
$$
BEGIN
NEW.new_notification_id = NEW.notification_id;
RETURN NEW;
END;
$$
LANGUAGE plpgsql
SQL
execute(<<~SQL)
CREATE TRIGGER chat_mention_notifications_new_notification_id_trigger BEFORE INSERT ON chat_mention_notifications
FOR EACH ROW EXECUTE PROCEDURE mirror_chat_mention_notifications_notification_id()
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
class CopyChatMentionNotificationsNotificationIdValues < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
def up
min_id, max_id =
execute("SELECT MIN(notification_id), MAX(notification_id) FROM chat_mention_notifications")[
0
].values
batch_size = 10_000
(min_id..max_id).step(batch_size) { |start_id| execute <<~SQL.squish } if min_id && max_id
UPDATE chat_mention_notifications
SET new_notification_id = notification_id
WHERE notification_id >= #{start_id} AND notification_id < #{start_id + batch_size} AND new_notification_id != notification_id
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class CopyChatMentionNotificationsNotificationIdIndexes < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
def up
execute "DROP INDEX #{Rails.env.test? ? "" : "CONCURRENTLY "} IF EXISTS index_chat_mention_notifications_on_new_notification_id"
execute "CREATE UNIQUE INDEX #{Rails.env.test? ? "" : "CONCURRENTLY "} index_chat_mention_notifications_on_new_notification_id ON chat_mention_notifications (new_notification_id)"
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
class SwapBigintChatMentionNotificationsNotificationId < ActiveRecord::Migration[7.1]
def up
# Necessary to rename and drop trigger/function
Migration::SafeMigrate.disable!
# Drop trigger and function used to replicate new values
execute "DROP TRIGGER chat_mention_notifications_new_notification_id_trigger ON chat_mention_notifications"
execute "DROP FUNCTION mirror_chat_mention_notifications_notification_id()"
# Swap columns
execute "ALTER TABLE chat_mention_notifications RENAME COLUMN notification_id TO old_notification_id"
execute "ALTER TABLE chat_mention_notifications RENAME COLUMN new_notification_id TO notification_id"
# Drop old indexes
execute "DROP INDEX index_chat_mention_notifications_on_notification_id"
execute "ALTER INDEX index_chat_mention_notifications_on_new_notification_id RENAME TO index_chat_mention_notifications_on_notification_id"
execute "ALTER TABLE chat_mention_notifications ALTER COLUMN old_notification_id DROP NOT NULL"
execute "ALTER TABLE chat_mention_notifications ALTER COLUMN notification_id DROP DEFAULT"
# Keep old column and mark it as read only
Migration::ColumnDropper.mark_readonly(:chat_mention_notifications, :old_notification_id)
ensure
Migration::SafeMigrate.enable!
end
def down
raise ActiveRecord::IrreversibleMigration
end
end