From 82e75c8700f4da7bccba6defa11b4b69b0f8ac3c Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Tue, 27 Aug 2024 19:57:16 +0800 Subject: [PATCH] DEV: Migrate `Chat::NotificationMention#notification_id` to `bigint` (#28571) `Notification#id` was migrated to `bigint` in 799a45a291e9f2bd94278f565e58874458768079 --- .../app/models/chat/mention_notification.rb | 8 +++-- ...cation_id_to_chat_mention_notifications.rb | 29 +++++++++++++++++ ...on_notifications_notification_id_values.rb | 22 +++++++++++++ ...n_notifications_notification_id_indexes.rb | 13 ++++++++ ...t_mention_notifications_notification_id.rb | 31 +++++++++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 plugins/chat/db/migrate/20240827040131_add_new_notification_id_to_chat_mention_notifications.rb create mode 100644 plugins/chat/db/migrate/20240827040550_copy_chat_mention_notifications_notification_id_values.rb create mode 100644 plugins/chat/db/migrate/20240827040810_copy_chat_mention_notifications_notification_id_indexes.rb create mode 100644 plugins/chat/db/migrate/20240827040811_swap_bigint_chat_mention_notifications_notification_id.rb diff --git a/plugins/chat/app/models/chat/mention_notification.rb b/plugins/chat/app/models/chat/mention_notification.rb index 0f4f90b9c8c..31a5bb8f2e8 100644 --- a/plugins/chat/app/models/chat/mention_notification.rb +++ b/plugins/chat/app/models/chat/mention_notification.rb @@ -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 # diff --git a/plugins/chat/db/migrate/20240827040131_add_new_notification_id_to_chat_mention_notifications.rb b/plugins/chat/db/migrate/20240827040131_add_new_notification_id_to_chat_mention_notifications.rb new file mode 100644 index 00000000000..c354cf61e50 --- /dev/null +++ b/plugins/chat/db/migrate/20240827040131_add_new_notification_id_to_chat_mention_notifications.rb @@ -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 diff --git a/plugins/chat/db/migrate/20240827040550_copy_chat_mention_notifications_notification_id_values.rb b/plugins/chat/db/migrate/20240827040550_copy_chat_mention_notifications_notification_id_values.rb new file mode 100644 index 00000000000..9fa7918731a --- /dev/null +++ b/plugins/chat/db/migrate/20240827040550_copy_chat_mention_notifications_notification_id_values.rb @@ -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 diff --git a/plugins/chat/db/migrate/20240827040810_copy_chat_mention_notifications_notification_id_indexes.rb b/plugins/chat/db/migrate/20240827040810_copy_chat_mention_notifications_notification_id_indexes.rb new file mode 100644 index 00000000000..b722a745d30 --- /dev/null +++ b/plugins/chat/db/migrate/20240827040810_copy_chat_mention_notifications_notification_id_indexes.rb @@ -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 diff --git a/plugins/chat/db/migrate/20240827040811_swap_bigint_chat_mention_notifications_notification_id.rb b/plugins/chat/db/migrate/20240827040811_swap_bigint_chat_mention_notifications_notification_id.rb new file mode 100644 index 00000000000..2433d2391bd --- /dev/null +++ b/plugins/chat/db/migrate/20240827040811_swap_bigint_chat_mention_notifications_notification_id.rb @@ -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