DEV: Migrate User#seen_notification_id to bigint (#28572)

`Notification#id` was migrated to `bigint` in 799a45a291
This commit is contained in:
Alan Guo Xiang Tan 2024-08-27 19:32:55 +08:00 committed by GitHub
parent 7335b44d4f
commit 4a6fc45429
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 85 additions and 2 deletions

View File

@ -1,6 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class User < ActiveRecord::Base class User < ActiveRecord::Base
self.ignored_columns = [
:old_seen_notification_id, # TODO: Remove when column is dropped. At this point, the migration to drop the column has not been written.
]
include Searchable include Searchable
include Roleable include Roleable
include HasCustomFields include HasCustomFields
@ -2251,7 +2255,6 @@ end
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# name :string # name :string
# seen_notification_id :integer default(0), not null
# last_posted_at :datetime # last_posted_at :datetime
# password_hash :string(64) # password_hash :string(64)
# salt :string(32) # salt :string(32)
@ -2287,6 +2290,7 @@ end
# last_seen_reviewable_id :integer # last_seen_reviewable_id :integer
# password_algorithm :string(64) # password_algorithm :string(64)
# required_fields_version :integer # required_fields_version :integer
# seen_notification_id :bigint default(0), not null
# #
# Indexes # Indexes
# #

View File

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

View File

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

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
class SwapSeenNotificationIdWithSeenNotificationIdOnUsers < ActiveRecord::Migration[7.1]
def up
# Necessary to rename and drop columns
Migration::SafeMigrate.disable!
# Drop trigger and function used to replicate new values
execute "DROP TRIGGER users_seen_notification_id_trigger ON users"
execute "DROP FUNCTION mirror_users_seen_notification_id()"
# Swap columns
execute "ALTER TABLE users RENAME COLUMN seen_notification_id TO old_seen_notification_id"
execute "ALTER TABLE users RENAME COLUMN new_seen_notification_id TO seen_notification_id"
execute "ALTER TABLE users ALTER COLUMN old_seen_notification_id DROP NOT NULL"
execute "ALTER TABLE users ALTER COLUMN old_seen_notification_id DROP DEFAULT"
# Keep old column and mark it as read only
Migration::ColumnDropper.mark_readonly(:users, :old_seen_notification_id)
ensure
Migration::SafeMigrate.enable!
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -259,7 +259,12 @@ task "db:migrate" => %w[
ActiveRecord::Tasks::DatabaseTasks.migrate ActiveRecord::Tasks::DatabaseTasks.migrate
SeedFu.quiet = true SeedFu.quiet = true
SeedFu.seed(SeedHelper.paths, SeedHelper.filter)
begin
SeedFu.seed(SeedHelper.paths, SeedHelper.filter)
rescue => error
error.backtrace.each { |l| puts l }
end
Rake::Task["db:schema:cache:dump"].invoke if Rails.env.development? && !ENV["RAILS_DB"] Rake::Task["db:schema:cache:dump"].invoke if Rails.env.development? && !ENV["RAILS_DB"]